% \iffalse meta-comment % SPDX-FileCopyrightText: Copyright (c) 2022-2026 Yegor Bugayenko % SPDX-License-Identifier: MIT % \fi % \CheckSum{0} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % \GetFileInfo{ppt-slides.dtx} % \DoNotIndex{\endgroup,\begingroup,\let,\else,\s,\n,\r,\\,\1,\fi} % \iffalse %<*driver> \ProvidesFile{ppt-slides.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{ppt-slides} %<*package> [2026-05-19 0.7.0 Slide Decks a la Power Point] % %<*driver> \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage{lmodern} \usepackage{microtype} \AddToHook{env/verbatim/begin}{\microtypesetup{protrusion=false}} \usepackage{graphicx} \usepackage{xcolor} \usepackage[runs=2,dtx,margin=0,small]{docshots} \usepackage{href-ul} \PageIndex \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{ppt-slides.dtx} \PrintChanges \PrintIndex \end{document} % % \fi % \title{|ppt-slides|: \LaTeX{} Package for \\ Slide Decks \`{a} la PowerPoint\thanks{The sources are in GitHub at \href{https://github.com/yegor256/ppt-slides}{yegor256/ppt-slides}}} % \author{Yegor Bugayenko \\ \texttt{yegor256@gmail.com}} % \date{\filedate, \fileversion} % % \maketitle % % \section{Introduction} % % This package renders slide decks in the PowerPoint\texttrademark{} style: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \begin{pptMiddle} % \pptTitle{Hello, world!}{How are you?} % \end{pptMiddle} % \end{document} % \end{docshot} % It is recommended that this package be employed in conjunction with % \href{https://github.com/yegor256/clicks}{clicks}: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \usepackage[static]{clicks} % \begin{document} % Slide decks may be composed in \LaTeX: % \plick{\pptBanner{Making Slides Is Easy}} % \plick{Simply employ this package\ldots} % \plush{together with the 'clicks' package.} % The result resembles what PowerPoint % produces, yet with the precision of \LaTeX. % Use in concert with ``clicks'' is recommended. % \end{document} % \end{docshot} % \section{Layout} % \DescribeMacro{\pptToc} % \DescribeMacro{\pptChapter} % First, the narrative is divided into chapters: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{clicks} \usepackage[template,scheme=light]{ppt-slides} \begin{document} \pptToc \plush{\pptChapter{About Me}} ... \plush{\pptChapter[Idea]{My Idea Is Novel}} ... \plush{\pptChapter[FAQ]{Discussion \& Questions}} ... \end{document} \end{verbatim} %\iffalse % %\fi % |\pptToc| renders the table of contents in an interactive ``clickable'' format. % Through the use of \href{https://github.com/yegor256/crumbs}{crumbs}, a navigation % appears at the upper left corner. % \DescribeMacro{\pptSection} % Sections are then placed within chapters: %\iffalse %<*verb> %\fi \begin{verbatim} \begin{document} \pptToc \plush{\pptChapter{About Me}} \plush{\pptSection[Student]{I'm a Student}} ... \plush{\pptSection[Athlete]{Also, I'm an Athlete}} ... \plush{\pptChapter[Idea]{My Idea Is Novel}} \plush{\pptSection{Novelty}} \plush{\pptSection{Impact}} \end{document} \end{verbatim} %\iffalse % %\fi % The |\pptChapter| and |\pptSection| commands employed in tandem render % an elegant two-level navigation menu at the upper left corner. % \DescribeMacro{\pptLeft} % \DescribeMacro{\pptRight} % The title of the presentation and the author's name may be placed at the foot % of each slide, on the left and on the right respectively: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage{clicks} \usepackage[template,scheme=light]{ppt-slides} \pptLeft{How Did I Spend Last Summer} \pptRight{Yegor Bugayenko} \begin{document} ... \end{document} \end{verbatim} %\iffalse % %\fi % Should neither the |\pptLeft| nor the |\pptRight| command be used, nothing % is printed at the foot. % \section{Commands} % \DescribeMacro{\pptPic} % An image may be added to a slide (the first argument denotes the width % of the image relative to |\textwidth|, while the second supplies its path): % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \pptPic{0.2}{socrates.jpg} \\ % This is Socrates, a Greek philosopher. % \end{document} % \end{docshot} % \DescribeMacro{\pptHeader} % A code fragment may be added to a slide (the use of \href{https://github.com/yegor256/ffcode}{ffcode} is recommended): % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \usepackage{ffcode} % \begin{document} % \pptHeader{This is How You Print to Console:} % \begin{ffcode} % void main(char** args) { % printf("Hello, world!"); % } % \end{ffcode} % \end{document} % \end{docshot} % |\plick| or |\plush| should not be used here, as they do not function with code snippets. % The |\pptHeader| command prints a header similar to that produced by the |\pptSection| command, % yet without commencing a new section. % \DescribeMacro{\pptQuote} % \DescribeMacro{\pptBanner} % A quotation may be placed beside an image by means of the |\pptQuote| command: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \pptBanner{A Cherished Quote} % \pptQuote{socrates.jpg}{The only true wisdom % lies in knowing that one knows nothing}{Socrates} % \end{document} % \end{docshot} % \DescribeMacro{\pptThought} % For a noteworthy thought to be placed at the centre of the slide, |\pptThought| is employed: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \pptThought{Socrates said that the only true % wisdom lies in knowing that one knows nothing. % Was he a wise man?...} % \end{document} % \end{docshot} % \DescribeMacro{pptMiddle} % Content may be positioned vertically at the centre of the page by means of the |pptMiddle| environment: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \begin{pptMiddle} % ``One's time is limited; it ought not be % wasted living someone else's life.'' --- Steve Jobs % \end{pptMiddle} % \end{document} % \end{docshot} % \DescribeMacro{\pptQR} % On occasion, it is more convenient to present a QR code to the audience in lieu of % a URL, since the former is more readily consulted---it may simply be scanned: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % The blog post may be consulted at: \\ % \pptQR{https://www.yegor256.com} % \end{document} % \end{docshot} % The code is rendered thus by virtue of the \href{https://ctan.org/pkg/qrcode}{qrcode} package % employed internally. % \DescribeMacro{pptWide} % \DescribeMacro{pptWideOne} % Slide content occasionally needs to occupy the entire visible horizontal width: % \begin{docshot} % \documentclass{article} % \usepackage[template,scheme=dark]{ppt-slides} % \begin{document} % \begin{pptWideOne} % This paragraph happens to be unusually long, % and must therefore occupy the entire visible % horizontal width, although the content % ordinarily bears a generous left margin. % \end{pptWideOne} % \end{document} % \end{docshot} % The form |\begin{pptWide}{X}| is likewise admissible, % where |X| denotes the number of columns to be rendered. % \section{Package Options} % \DescribeMacro{template} % Each slide deck begins with a template: %\iffalse %<*verb> %\fi \begin{verbatim} \documentclass{article} \usepackage[template=9x6]{ppt-slides} \begin{document} ... \end{document} \end{verbatim} %\iffalse % %\fi % Only one template is supplied and is used by default: |9x6|. Should the % name be omitted, this template is selected. Should the |template| option % itself be omitted entirely, the default |article| is rendered, which is % rarely the desired outcome. % \DescribeMacro{scheme} % A colour scheme for the slides may be selected by means of the |scheme| option % of the package: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[template,scheme=light]{ppt-slides} \end{verbatim} %\iffalse % %\fi % Several schemes are available out of the box: |light|, |dark|, % |light-mono|, and |dark-mono|. A bespoke scheme may also be devised, taking % the |ppt-light.tex| file as a model: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[template,scheme=/usr/local/my-colors.tex]{ppt-slides} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{directory} % The location of the templates and schemes may be altered by means of the |directory| package option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[directory=/tmp,template=foo]{ppt-slides} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{nominutes} % By default, when the slide deck is rendered in non-static mode (the |static| option of the ``clicks'' package being absent), % a minute tracker appears at the upper right corner of each slide. This may be disabled % by means of the |nominutes| option of the package: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[nominutes]{ppt-slides} \end{verbatim} %\iffalse % %\fi % \DescribeMacro{nocrumbs} % By default, the upper left corner of each slide bears so-called crumbs. These may be removed % by means of the |nocrumbs| package option: %\iffalse %<*verb> %\fi \begin{verbatim} \usepackage[nocrumbs]{ppt-slides} \end{verbatim} %\iffalse % %\fi % \StopEventually{} % \section{Implementation} % \changes{0.0.1}{2022/09/11}{First draft.} % \changes{0.1.4}{2022/09/15}{The \texttt{nominutes} package option added.} % \changes{0.1.5}{2022/09/19}{The default directory fixed.} % \changes{0.2.0}{2022/12/03}{We migrated to the \texttt{ltxdoc} format and \texttt{.dtx} file.} % \changes{0.5.0}{2025/04/17}{The \texttt{nocrumbs} package option was introduced.} % First, we parse the package options: % \begin{macrocode} \RequirePackage{pgfopts} \makeatletter \pgfkeys{ /ppt-slides/.is family, /ppt-slides, template/.estore in = \ppt@template, template/.default = 9x6, scheme/.estore in = \ppt@scheme, directory/.estore in = \ppt@directory, directory/.default = , nominutes/.estore in = \ppt@nominutes, nocrumbs/.estore in = \ppt@nocrumbs, directory } \ProcessPgfPackageOptions{/ppt-slides} \makeatother % \end{macrocode} % Then, we include the template: % \begin{macrocode} \makeatletter\ifdefined\ppt@template \input{\ppt@directory ppt-templates/ppt-\ppt@template.tex} \else \message{^^Jppt: No template is loaded, because the 'template' option is not specified} \fi\makeatother % \end{macrocode} % Then, we include the scheme: % \begin{macrocode} \makeatletter\ifdefined\ppt@scheme \RequirePackage{xcolor} \input{\ppt@directory ppt-schemes/ppt-\ppt@scheme.tex} \else \message{^^Jppt: No color scheme is loaded, because the 'scheme' option is not specified} \fi\makeatother % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/ifthen}{ifthen} % in order to enable |if/then/else| commands: % \begin{macrocode} \RequirePackage{ifthen} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/href-ul}{href-ul} % in order to enable underlined hyperlinks: % \begin{macrocode} \RequirePackage{href-ul} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/pagecolor}{pagecolor} % in order to make it possible to change the background color of a page: % \begin{macrocode} \RequirePackage{pagecolor} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/varwidth}{varwidth} % in order to change the width of the page, inside |pptWide|: % \begin{macrocode} \RequirePackage{varwidth} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/csquotes}{csquotes} % in order to use double quotes: % \begin{macrocode} \RequirePackage{csquotes} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/qrcode}{qrcode} % in order to render QR codes: % \begin{macrocode} \RequirePackage{qrcode} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/tikz}{tikz} % in order to position elements on the page, especially in the Table of Contents: % \begin{macrocode} \RequirePackage{tikz} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/tikzpagenodes}{tikzpagenodes} % in order to pin a block in |\pptPin|: % \begin{macrocode} \RequirePackage{tikzpagenodes} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/enumitem}{enumitem} % in order to render inline lists in crumbs: % \begin{macrocode} \PassOptionsToPackage{inline}{enumitem} \RequirePackage{enumitem} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/crumbs}{crumbs} % in order to show top-page menus: % \begin{macrocode} \RequirePackage{crumbs} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/calc}{calc} % in order to calculate positions of elements more precisely: % \changes{0.3.1}{2024/01/13}{The \texttt{calc} package added.} % \begin{macrocode} \RequirePackage{calc} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/tabularx}{tabularx} % in order to render |\pptQuote|: % \begin{macrocode} \RequirePackage{tabularx} % \end{macrocode} % Then, we include \href{https://ctan.org/pkg/seqsplit}{seqsplit} % in order to split long links: % \begin{macrocode} \RequirePackage{seqsplit} % \end{macrocode} % \begin{macro}{\pptMiddle} % \changes{0.2.1}{2022/12/04}{The \texttt{\char`\\pptMiddle} command turned into \texttt{pptMiddle} environment.} % Then, we define the |pptMiddle| environment: % \begin{macrocode} \newenvironment{pptMiddle} {\vspace*{\fill}} {\vspace*{\fill}} % \end{macrocode} % \end{macro} % \begin{macro}{\pptBanner} % Then, we define the |\pptBanner| command: % \begin{macrocode} \newcommand\pptBanner[2][green]{% \par% {\setlength{\fboxsep}{6pt}% \colorbox{#1}{\color{\thepagecolor}\large #2}}% \par% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptChapter} % \changes{0.4.0}{2024/10/18}{The \texttt{\char`\\pptChapterLabel} command introduced.} % Then, we define the |\pptChapter| and |\pptChapterLabel| commands: % \begin{macrocode} \newcommand\pptChapterLabel{Chapter} \newcommand\pptChapter[2][]{% \crumbection[#1]{#2}% \begin{pptMiddle}% {\large\ttfamily \pptChapterLabel{} \#\the\value{section}:}% \newline% \rotatebox{1}{\pptBanner[blue]{\LARGE#2}}% \end{pptMiddle}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptSection} % Then, we define the |\pptSection| command: % \begin{macrocode} \newcommand\pptSection[2][]{% \subcrumbection[#1]{#2}% \pptHeader{#2}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptHeader} % Then, we define the |\pptHeader| command: % \begin{macrocode} \newcommand\pptHeader[1]{% \vspace*{-0.75in}\hspace*{-0.5in}% \rotatebox{1}{\pptBanner[orange]{\Large #1}}\vspace*{0.15in}% \par% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptTitle} % Then, we define the |\pptTitle| command, which prints the |title| and |subtitle| on the % first page. The first argument is the title, the second is the subtitle. If the second % argument is empty, it won't be printed: % \begin{macrocode} \newcommand\pptTitle[2]{% {\pptBanner{\Huge #1}}% \def\param{#2}% \ifx\param\empty\else% {\pptBanner{\large #2}}% \fi% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptToc} % Then, we define the |\pptToc| command: % \begin{macrocode} \newcommand*\pptTOC{} \newcommand\pptToc[1][]{% \renewcommand*\pptTOC{}% \print{% \def\param{#1}% \ifx\param\empty\else% \pptBanner{#1}% \fi% \tikz{% \node (z) {% \begin{varwidth}{\textwidth}% \ifx\pptTOC\empty\else% \begin{itemize}[label={}] \pptTOC \end{itemize} \fi% \end{varwidth}% };% \path [draw=blue,line width=4pt] (z.north west) -- (z.south west);% }% }% \begin{@empty}% \renewcommand\crumb[2]{% \ifx\pptTOC\empty\else\ifdefined\click\click[0]\fi\fi \gappto\pptTOC{\item ##2} } \crumbs \end{@empty}% \ifdefined\flush\flush[1]\fi% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptQuote} % Then, we define the |\pptQuote| command, with one optional and three mandatory arguments: % \changes{0.3.0}{2023/11/08}{The \texttt{\char`\\pptQuote} command has got an optional parameter, where the name of the person on the photo can be specified.} % \begin{macrocode} \newcommand\pptQuote[4][]{% \begin{tabularx}{\columnwidth}{c>{\raggedright\arraybackslash}X}% \raisebox{\dimexpr-\height+\ht\strutbox}{ \parbox{0.25\textwidth+2pt}{% \raggedright% \pptPic{0.25}{#2}% \def\person{#1}% \ifx\person\empty\else% \par% \small% \person% \fi% }% }% &% \enquote{#3{}}% \def\param{#4}% \ifx\param\empty\else% \par\vspace*{1em}% \small% \textemdash{} \param% \par% \fi% \\% \end{tabularx}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptPic} % Then, we define the |\pptPic| command: % \begin{macrocode} \newcommand\pptPic[2]{% {% \setlength{\fboxsep}{0pt}% \setlength{\fboxrule}{1pt}% \fcolorbox{gray}{white}{% \includegraphics[width=#1\columnwidth]{#2}% }% }% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptPin} % Then, we define the |\pptPin| command: % \begin{macrocode} \newcommand\pptPin[2][right]{% \begin{tikzpicture}[remember picture,overlay]% \ifthenelse{\equal{#1}{left}}% {% \node[anchor=north east] at ($(current page text area.north west) - (24pt, 18pt)$) {% \begin{minipage}{0.25\textwidth}% \raggedleft #2% \end{minipage}% };% }% {% \node[anchor=north east] at (current page text area.north east) {% \begin{minipage}{0.25\textwidth}% \raggedright #2% \end{minipage}% };% }% \end{tikzpicture}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptThought} % \changes{0.3.0}{2023/09/19}{The \texttt{\char`\\pptThought} command aligns text to the left.} % Then, we define the |\pptThought| command: % \begin{macrocode} \newcommand\pptThought[1]{% \begin{pptMiddle}% \tikz{% \node [inner sep=18pt] (z) {% \begin{varwidth}{0.8\textwidth}% \raggedright\Large #1% \end{varwidth}% }; \path [draw=green,line width=8pt] (z.north west) -- (z.south west); }% \end{pptMiddle}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptPunch} % \changes{0.7.0}{2026/05/19}{The \texttt{\char`\\pptPunch} command places content right % in the middle of the slide, both vertically and horizontally.} % Then, we define the |\pptPunch| command: % \begin{macrocode} \newcommand\pptPunch[1]{% \begin{textblock}{16}[0.5,0.5](8,8)% \centering #1% \end{textblock}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptSnippet} % Then, we define the |\pptSnippet| command: % \begin{macrocode} \newcommand\pptSnippet[2][\small]{% \begin{samepage}% #1\verbatiminput{#2}% \end{samepage}% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptQR} % Then, we define the |\pptQR| command: % \begin{macrocode} \newcommand\pptQR[2][2in]{% \tikz{% \node[draw=white]{% \href{#2}{% \qrcode[height=#1]{#2}% }% }% }% } % \end{macrocode} % \end{macro} % \begin{macro}{\pptPinQR} % Then, we define the |\pptPinQR| command: % \begin{macrocode} \newcommand\pptPinQR[2][right]{% \pptPin[#1]{% \begin{minipage}{1.4in}% \raggedleft% \pptQR[1in]{#2}% \\[3pt] \ttfamily\fontsize{8pt}{10pt}\selectfont% \seqsplit{#2} \href{#2}{$\rightarrow$}% \\ \end{minipage}% }% } % \end{macrocode} % \end{macro} % \begin{macro}{pptWide} % Finally, we define the |pptWide| and |pptWideOne| environments: % \begin{macrocode} \newenvironment{pptWideOne} {\begin{adjustwidth}{-2in}{-1in}} {\end{adjustwidth}} \newenvironment{pptWide}[1] {\begin{pptWideOne}\begin{multicols}{#1}} {\end{multicols}\end{pptWideOne}} % \end{macrocode} % \end{macro} % \begin{macrocode} \endinput % \end{macrocode} % \Finale % \PrintChanges % \clearpage % \PrintIndex