16
\$\begingroup\$

Many people swear by Scribus as the best tool for creating RPG-related materials, but hold on a second. What about using a classical programming-style typesetting language like LaTeX for this purpose? There is plenty of free layout source code available to download and adapt, so you wouldn't have to build the whole typesetting of an entire character sheet or RPG book from scratch.

Is it possible to use LaTeX for projects like these?

New contributor
NESRockman1987 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
19
  • 2
    \$\begingroup\$ Sorry, but this is a quintessential tool recommendation, or opinion question, both of which is not allowed on the stack. \$\endgroup\$ Commented 2 days ago
  • 4
    \$\begingroup\$ No, but it does mean that (if the community agrees with Trish, as seems likely), the question will be closed, so no one will be able to answer it. You will still be able to see it and edit it, and if you edit it to something acceptable to the community, it can be reopened. But I’m not sure there’s an obvious edit of this question that will work—what you really seem to want is a discussion, which our format can’t handle. Perhaps try Role-playing Games Chat? (I have no idea how active that is these days though...) \$\endgroup\$ Commented 2 days ago
  • 2
    \$\begingroup\$ Also, for the record, I’ve upvoted your question—whether or not we can handle it, it is a good question, and a discussion of this would be interesting to me. I’m just not sure it can fit here. \$\endgroup\$ Commented 2 days ago
  • 8
    \$\begingroup\$ LaTeX is the solution to EVERYTHING. I have an answer to your question, supported by my experience in using it for DnD. But I will wait for the response of the community, since it is likely to be closed. \$\endgroup\$ Commented 2 days ago
  • 6
    \$\begingroup\$ I see where Trish is coming from, but I very respectfully disagree. At least if the final paragraph is removed this is essentially asking "Is X a useful approach to achieve Y?" which is a type of question addressed here often, and answering it requires at least some familiarity with RPG books. \$\endgroup\$ Commented 2 days ago

2 Answers 2

18
\$\begingroup\$

Yes, and it is wonderful.

I used the \$\LaTeX\$ class dndbook available here for several projects, available also on overleaf. I employed it for RPG books and adventure/campaign booklets.

I have a little bit of experience with LaTeX due to my work, and I find it intuitive and easy. This is not the same for people used to using Word or other similar horrors... I mean, typesetting software.

This is just an example of what you can do: this is a page of a chapter of a book. If you look at the documentation, there are pre-made commands for feats, spells, monster stat blocks and others. I think it is a very good class for \$\LaTeX\$.

example image of a supplement written in LaTeX

A not-so-wonderful Character Sheet

For the character sheet, I saw this class, but I do not have any experience with it.

I manage to create a very rough and bad-looking char sheet, using the package eforms, trying to make it a little bit more appealing with tikz (for the skill proficiencies). The code is below the screenshot.

screenshot of the char sheet

This document allows to

  • set the ability scores
  • set the proficiency bonus
  • set the skill in which the character is proficient

It computes automatically the ability modifiers, and updates the skill modifiers, the AC and the max HPs. The appearance is terrible, but with some work with tikz I believe that one can obtain some interesting result.

\documentclass{article}

\usepackage{eforms} 

\usepackage{tikz}

\newcommand{\mycircle}[1]{
\begin{tikzpicture}
    \draw[fill=none] (0,0) circle (6.5pt);
    \node at (0,0) {#1};
\end{tikzpicture}
} 


\begin{document}
    
    \section*{Plain Character Sheet}
    
    
    
    
    \medskip
    
    \begin{minipage}{0.5\textwidth}
        
        \TextField[
        name=PB,
        readonly=false,
        width=0.3\linewidth,
        value={2},
        bordercolor={0.5 0 0.5}
        ]{Proficiency  Bonus}
        
        \medskip 
        
        
        \begin{tabular}{cccc}
            \TextField[
            name=AC,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=AC,
            bordercolor={1 1 1}]{}& 
            \TextField[
            name=ACvalue,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=10,
            bordercolor={0 0 1},
            ]{}&
            
            \TextField[
            name=HPs,
            width=1.2cm,
            height=0.8cm,
            readonly=true,
            value=maxHPs,
            bordercolor={1 1 1}]{}& 
            \TextField[
            name=HPsValue,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value=8,
            bordercolor={0 0 1},
            ]{}\\
        \end{tabular}
        
        \subsection*{Ability Scores}
        
        
        \begin{tabular}{ccc}
            \TextField[
            name=str,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=STR,
            bordercolor={1 1 1}
            ]{} & \TextField[
            name=STR,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("STR").value; var B = (parseInt(A)-10)/2 ; this.getField("STRBonus").value=Math.floor(B);},
            ]{} & \TextField[
            name=STRBonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}\\
            
            \TextField[
            name=dex,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=DEX,
            bordercolor={1 1 1}
            ]{}&
            \TextField[
            name=DEX,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("DEX").value; var B = (parseInt(A)-10)/2 ; this.getField("DEXBonus").value=Math.floor(B); this.getField("ACvalue").value=10+Math.floor(B);},
            ]{}&
            \TextField[
            name=DEXBonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}\\
            
            \TextField[
            name=con,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=CON,
            bordercolor={1 1 1}
            ]{}&
            \TextField[
            name=CON,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("CON").value; var B = (parseInt(A)-10)/2 ; this.getField("CONBonus").value=Math.floor(B);this.getField("HPsValue").value=8+Math.floor(B);},
            ]{}&
            \TextField[
            name=CONBonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}\\
            \TextField[
            name=int,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=INT,
            bordercolor={1 1 1}
            ]{}&
            \TextField[
            name=INT,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("INT").value; var B = (parseInt(A)-10)/2 ; this.getField("INTBonus").value=Math.floor(B);},
            ]{}&
            \TextField[
            name=INTBonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}\\
            \TextField[
            name=wis,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=WIS,
            bordercolor={1 1 1}
            ]{}&
            \TextField[
            name=WIS,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("WIS").value; var B = (parseInt(A)-10)/2 ; this.getField("WISBonus").value=Math.floor(B);},
            ]{}&
            \TextField[
            name=WISBonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}\\
            \TextField[
            name=cha,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value=CHA,
            bordercolor={1 1 1}
            ]{}&
            \TextField[
            name=CHA,
            width=0.8cm,
            height=0.8cm,
            readonly=false,
            value={10},
            calculate={var A = this.getField("CHA").value; var B = (parseInt(A)-10)/2 ; this.getField("CHABonus").value=Math.floor(B);},
            ]{}&
            \TextField[
            name=CHABonus,
            width=0.8cm,
            height=0.8cm,
            readonly=true,
            value={0}
            ]{}
        \end{tabular}
        
        
        
        
        
    \end{minipage}\begin{minipage}{0.5\textwidth}
    \begin{tabular}{lll}
        
        \mycircle{\CheckBox[
        name=AcroPB,
        value=Off,
        width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}
        ]{}}& Acrobatics & \TextField[
        name=AcroBonus,
        readonly=true,
        value={0},
        calculate={var A = this.getField("DEXBonus").value; var B= 0; if (this.getField("AcroPB").value === "Yes"){B = this.getField("PB").value;} this.getField("AcroBonus").value=A+B;},
        ]{}\\
        
        \mycircle{\CheckBox[name=AnHPB,value=Off,width=7pt,
            height=7pt,
            checkboxsymbol=l,
            bordercolor={1 1 1}]{}} & Animal Handling &
        \TextField[
        name=AnHBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("WISBonus").value;
            var B=0;
            if(this.getField("AnHPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=ArcPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Arcana &
        \TextField[
        name=ArcBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("INTBonus").value;
            var B=0;
            if(this.getField("ArcPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        
        
        
        
        \mycircle{\CheckBox[
        name=AthlPB,
        value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}
        ]{}}& Athletics&
        \TextField[
        name=AthlBonus,
        readonly=true,
        value={0},
        calculate={var A = this.getField("STRBonus").value; var B= 0; if (this.getField("AthlPB").value === "Yes"){B = this.getField("PB").value;} this.getField("AthlBonus").value=A+B;}
        ]{}\\
        
        \mycircle{\CheckBox[name=DecPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Deception &
        \TextField[
        name=DecBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("CHABonus").value;
            var B=0;
            if(this.getField("DecPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=HisPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & History &
        \TextField[
        name=HisBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("INTBonus").value;
            var B=0;
            if(this.getField("HisPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=InsPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Insight &
        \TextField[
        name=InsBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("WISBonus").value;
            var B=0;
            if(this.getField("InsPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=IntPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Intimidation &
        \TextField[
        name=IntBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("CHABonus").value;
            var B=0;
            if(this.getField("IntPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=InvPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Investigation &
        \TextField[
        name=InvBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("INTBonus").value;
            var B=0;
            if(this.getField("InvPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=MedPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Medicine &
        \TextField[
        name=MedBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("WISBonus").value;
            var B=0;
            if(this.getField("MedPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=NatPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Nature &
        \TextField[
        name=NatBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("INTBonus").value;
            var B=0;
            if(this.getField("NatPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=PerPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Perception &
        \TextField[
        name=PerBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("WISBonus").value;
            var B=0;
            if(this.getField("PerPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        
        \mycircle{\CheckBox[name=PerfPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Performance &
        \TextField[
        name=PerfBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("CHABonus").value;
            var B=0;
            if(this.getField("PerfPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=PersPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Persuasion &
        \TextField[
        name=PersBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("CHABonus").value;
            var B=0;
            if(this.getField("PersPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=RelPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Religion &
        \TextField[
        name=RelBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("INTBonus").value;
            var B=0;
            if(this.getField("RelPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=SoHPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Sleight of Hand &
        \TextField[
        name=SoHBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("DEXBonus").value;
            var B=0;
            if(this.getField("SoHPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        \mycircle{\CheckBox[name=StePB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Stealth &
        \TextField[
        name=SteBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("DEXBonus").value;
            var B=0;
            if(this.getField("StePB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        
        \mycircle{\CheckBox[name=SurPB,value=Off,width=7pt,
        height=7pt,
        checkboxsymbol=l,
        bordercolor={1 1 1}]{}} & Survival &
        \TextField[
        name=SurBonus,
        readonly=true,
        value={0},
        calculate={var A=this.getField("WISBonus").value;
            var B=0;
            if(this.getField("SurPB").value==="Yes"){B=this.getField("PB").value;}
            event.value = Number(A)+Number(B);}
        ]{} \\
        
        
        
        

        
    \end{tabular}
    

    
    
    \end{minipage}
    

    
    
\end{document}
\$\endgroup\$
10
  • 2
    \$\begingroup\$ Using LaTeX for an RPG book seems pretty straightforward—the part of the question that particularly interested me was the bit about character sheets. Can LaTeX do that? Can it handle making the PDF editable, or does it only lay out a printable sheet? (To be clear, +1 as is, just wondering if you know anything about this.) \$\endgroup\$ Commented 2 days ago
  • 2
    \$\begingroup\$ @KRyan I had to search a little bit, I remember the one linked but o never used it. I never needed it, but latex allows to make editable pdfs. \$\endgroup\$ Commented 2 days ago
  • 2
    \$\begingroup\$ did a grammar pass \$\endgroup\$ Commented 2 days ago
  • 2
    \$\begingroup\$ Thank you! Yeah I have seen the github previously. Bet if someone can modify the source code then he can do whatever he wants to do with it. Love to see a WoD character sheet' source in latex. \$\endgroup\$ Commented 2 days ago
  • 1
    \$\begingroup\$ @NESRockman1987 for WoD... one of the most commonly used is the set of MrGone... \$\endgroup\$ Commented 2 days ago
9
\$\begingroup\$

It certainly is possible to create a character sheet.

For example:

\documentclass[11pt]{article}

\usepackage[margin=1.5cm]{geometry}
\usepackage{array}
\usepackage{tabularx}
\usepackage{titlesec}
\usepackage[most]{tcolorbox}

\setlength{\parindent}{0pt}
\renewcommand{\familydefault}{\sfdefault}

\titleformat{\section}{\large\bfseries}{}{0pt}{}
\titlespacing*{\section}{0pt}{0.4em}{0.2em}

% Rounded field style
\tcbset{
  charfield/.style={
    colback=white,
    colframe=black,
    rounded corners,
    boxrule=0.6pt,
    left=3pt,right=3pt,top=3pt,bottom=3pt,
  },
}

\newcommand{\FieldBox}[2][]{%
  \begin{tcolorbox}[charfield,enhanced,breakable,title={#1}]
  #2
  \end{tcolorbox}%
}

\begin{document}

\begin{tabularx}{\textwidth}{@{}X X X@{}}
\FieldBox[Name]{\vspace*{1.2em}} &
\FieldBox[Class]{\vspace*{1.2em}} &
\FieldBox[Level]{\vspace*{1.2em}} \\
\end{tabularx}

\vspace{0.4em}

...

Renders like this:

First three fields

While this looks pretty basic, it just serves as a proof of concept. You can play around with the borders and font to make it look like you want, and of course add as many other fields as you wish.

To group fields you can use for example \begin{minipage} sections. For subtitles, something like \section*{Attributes}. Commands like \hline, \vspace and \begin{tabularx} sure will come in handily.

To create an editable PDF form with LaTeX, someone described the full approach here. It is based on \usepackage{hyperref} and elements like \TextField[name=name,width=3cm,charsize=12pt]. See also the docs on the hyperref package for more info.

Full disclosure: the LaTeX code above has been created by a LLM, but not the rest of the answer.

\$\endgroup\$
1
  • \$\begingroup\$ Some times ago I have done some interactive pdf that involved JavaScript, if I recall well. As soon as I reach home I will retrieve the code. \$\endgroup\$ Commented yesterday

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.