TeXMe is a lightweight JavaScript utility to create self-renderingMarkdown + LaTeX documents.
Copy and paste the code below into an HTML file with .html
as theextension name:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
This file contains one line of HTML code followed by Markdown + LaTeXcontent.
Open this HTML file with a web browser. It renders itself to look like this:get-started.html.Here is a screenshot of the output:
There are three simple rules to remember while using TeXMe:
TeXMe removes any leading and trailing whitespace in the contentbefore rendering the content to HTML.
TeXMe uses the first non-empty line of the content to set the pagetitle if no explicit <title>
element is specified. Any leading andtrailing whitespace and hash (#
) characters are removed whilesetting the page title.
If there is a Markdown element such as code span/block or image withLaTeX delimiters in it (e.g., $
, $$
, etc.), TeXMe may interpretit as LaTeX which may lead to incorrect rendering of the document.To prevent this issue, put such Markdown element within a specialpurpose md
environment supported by TeXMe, for example,\begin{md}`echo $foo`\end{md}
. If you do not have such Markdownelements with LaTeX delimiters, you may ignore this rule. See theMarkdown Priority Environmentsection to see more details about this. Note: For most documents,you don't have to worry about this point.
If you do not like to start your document with HTML tags, you can writeyour content first and add the <script>
tag in the end but thisapproach has some limitations. See the Content inBody section for more details about it.
Use the following URL in the <script>
tag to load version 1.0.0 (thecurrent version at this time) of TeXMe:
https://cdn.jsdelivr.net/npm/texme@1.0.0
Use the following URL in the <script>
tag to always load the latestversion of TeXMe:
https://cdn.jsdelivr.net/npm/texme
If you need something really easy to remember, use this URL to load thelatest version of TeXMe:
https://unpkg.com/texme
The Get Started section earlier shows how we can createa self-rendering document with a single line of HTML code but thisbrevity comes at the cost of standard conformance. For example, therequired <title>
element is missing from the code. Further the<textarea>
element is not closed.
For the sake of completeness and correctness, here is a minimal butcomplete and valid HTML5 example:
<!DOCTYPE html>
<html lang="en">
<title>Notes on Euler's Identity</title>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
<textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
</textarea>
Here is the output:valid-html5.html.
It has a few more lines of code to ensure that this HTML5 code validatessuccessfully at validator.w3.org. As a result, this exampledoes not look as concise as the one in the previous section.
In case you are wondering, a valid HTML5 document does not requireexplicit <head>
, <body>
, or the closing </html>
tags, so they havebeen omitted for the sake of brevity while maintaining completeness andcorrectness.
In practice though, it is not necessary to write verbose code like this.All browsers follow the robustness principle, so theycan render the shorter example in the Get Startedsection just fine.
TeXMe renders the document on a white pane against a gray background bydefault. This is due to a configuration option named style
that is setto 'viewer'
by default.
To render the document with a minimal style on a completely plain whitebackground, set the style
configuration option to 'plain'
. Here isan example:
<!DOCTYPE html>
<script>window.texme = { style: 'plain' }</script>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
Here is the output:style-plain.html.
To render the document with absolutely no style, set style
to'none'
. The 'none'
style option is useful to disable the default'viewer'
style set by TeXMe before defining a custom style withregular CSS code. Here is an example:
<!DOCTYPE html>
<script>window.texme = { style: 'none' }</script>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
<style>
body {
background: lightcyan;
}
main {
max-width: 20em;
padding: 1em;
border: medium double gray;
margin: 2em auto;
background: lightyellow;
}
</style>
<textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
Here is the output:style-custom.html.
Note that the rendered content is displayed within a <main>
elementinside the <body>
. That is why these elements are being styled in theabove example.
To render Markdown-only content without any mathematical content at all,set useMathJax
and protectMath
options to false
:
<!DOCTYPE html>
<script>window.texme = { useMathJax: false, protectMath: false }</script>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Atomic Theory
**Atomic theory** is a scientific theory of the nature of matter, which
states that matter is composed of discrete units called *atoms*. It
began as a philosophical concept in ancient Greece and entered the
scientific mainstream in the early 19th century when discoveries in the
field of chemistry showed that matter did indeed behave as if it were
made up of atoms.
Here is the output:markdown-only.html.
When TeXMe loads, it begins rendering the document automatically. Thisautomatic rendering may be skipped by setting renderOnLoad
option tofalse
. Here is an example that disables automatic rendering and theninvokes rendering later on the click of a button by using thetexme.renderPage()
function from the TeXMe API:
<!DOCTYPE html>
<script>window.texme = { renderOnLoad: false }</script>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
<script>
window.onload = function () {
var button = document.getElementById('button')
button.onclick = function () {
button.remove()
texme.renderPage()
}
}
</script>
<textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
</textarea>
<div><button id="button">Render</button></div>
Here is the output:skip-render.html.
When we load TeXMe with the <script>
tag, it begins rendering thedocument as soon as it loads. Therefore in the above examples, we definethe configuration options prior to loading TeXMe. We do this by definingan object named window.texme
with the configuration options defined asproperties in this project.
However if we set the renderOnLoad
option to false
, we prevent TeXMefrom rendering the document after it loads. We now have the control toinvoke the rendering at a later time, e.g., on the click of a button. Inthis case, it is possible to set configuration options after loadingTeXMe with the texme.setOption()
function. This function takes twoparameters: option name as a string and option value.
Here is an example that skips automatic rendering on load and sets thestyle to 'plain'
using this function:
<!DOCTYPE html>
<script>window.texme = { renderOnLoad: false }</script>
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
<script>
window.onload = function () {
var button = document.getElementById('button')
button.onclick = function () {
button.remove()
texme.setOption('style', 'plain')
texme.renderPage()
}
}
</script>
<textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
</textarea>
<div><button id="button">Render</button></div>
Here is the output:set-options.html.
If you do not like to start your document with HTML tags, you canwrite your content first and add the <script>
tag in the end likethis:
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
Here is the output:content-in-body.html.
Although, the code looks neater in this example, there is a limitationassociated with this form of writing content: Since the content is partof the HTML <body>
element (there is no <textarea>
element in thiscode), the content should be written carefully, so that it does not haveany HTML syntax error.
While using the content-in-body method of using TeXMe, an HTML syntaxerror in the content can produced mangled output. For example, thefollowing input is not rendered as expected because the content is inthe <body>
element, so the browser interprets this content as HTML andencounters the beginning of a start tag that is not closed properly:
Here is some unusual code:
```
print('unusual <string')
```
<script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script>
Here is the broken output:unusual-code-body.html.
The <string
part of the code is interpreted as the opening of a starttag by the browser. What looks like a fragment of Python code to a humanends up being parsed as an HTML tag by the browser that looks like this:
<string') ```="" <script="" src="https://cdn.jsdelivr.net/npm/texme@1.0.0">
This mangled form of the input is then rendered leading to unexpectedresults. To resolve this, put the content within a <textarea>
element(as shown in the very first example in this document). The followinginput is fine because the content is put inside a <textarea>
element.
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
Here is some unusual code:
```
print('unusual <string')
```
Here is the output:unusual-code-textarea.html.
Since the content occurs within the <textarea>
element, the browserdoes not parse it as HTML and therefore does not mangle it.
The examples so far use TeXMe as a utility. The previous examples loadTeXMe in a web page and then TeXMe automatically picks the <textarea>
element containing Markdown + LaTeX code and renders it as HTML.
In this section, we see how to use TeXMe as a library and invoke itsfunctions. These examples would run as is on Node.js.
Enter the following command to install TeXMe:
npm install texme
Markdown + LaTeX content can be rendered to HTML by simply invoking thetexme.render()
function. It accepts the Markdown + LaTeX content asa string and returns the rendered HTML as a string. Here is an example:
var texme = require('texme')
var input = '**Foo** $$ {a}_{1} {a}_{2} $$'
var output = texme.render(input)
console.log(output)
The above example produces the following output:
<p><strong>Foo</strong> $$ {a}_{1} {a}_{2} $$</p>
Here is a quick reference for all the supported configuration options:
useMathJax
(true
by default): Load MathJax and run it to renderLaTeX when set to true
. Do not load or run MathJax when set tofalse
.
protectMath
(true
by default): Prevent Markdown renderer fromseeing LaTeX code when set to true
. Therefore LaTeX contentthat may contain text that could be interpreted as Markdown(e.g., $$ {a}_{1} {a}_{2} $$
) remains intact as LaTeX when set totrue
. Let Markdown renderer look for Markdown text within LaTeXcode and render it when set to false
. For example,$$ {a}_{1} {a}_{2} $$
is rendered as<p>$$ {a}<em>{1} {a}</em>{2} $$</p>
when this option is set tofalse
.
style
('viewer'
by default): Three values are supported:'viewer'
, 'plain'
, and 'none'
. The viewer style displaysthe rendered document on a white pane against a gray background. Theplain style displays the content with a very minimal style that doesnot change the background style. If set to 'none'
, no stylewhatsoever is applied and the document is displayed with thebrowser's default style.
renderOnLoad
(true
by default): Begins rendering the documentautomatically on load when set to true
. Skips renderingautomatically when set to false
.
onRenderPage
(undefined
by default): A callback function that isautomatically invoked after TeXMe completes rendering the page. Itis guaranteed that TeXMe has completed rendering the page beforeinvoking this callback. If useMathJax
option is true
, it is alsoguaranteed that TeXMe has invoked typesetting LaTeX with MathJaxbefore invoking this callback. However it is not guaranteed thatMathJax has completed typesetting the page before this callback isinvoked. MathJax typesetting occurs asynchronously and may completeafter this callback is invoked. This callback runs only when thetexme.renderPage()
function runs in web browser either due toautomatic rendering on load or due to explicit call to thisfunction.
markdownURL
(CDN URL of minified marked.js by default): URL toload marked.js while running in a web browser.
MathJaxURL
(CDN URL of MathJax by default): URL to load MathJaxwhile running in a web browser.
Some users of TeXMe want to know if TeXMe can be hosted on one's ownweb server such that TeXMe does not load resources from any other webserver while rendering a document, i.e., any requests to loadresources must be made to the same web server from which TeXMe isloaded. Yes, it is possible to self-host TeXMe in this manner. Hereare the steps:
Clone copies of TeXMe and its dependencies to your own server at alocation from where you want to serve the files:
git clone https://github.com/susam/texme.git
git clone https://github.com/markedjs/marked.git
git clone https://github.com/mathjax/mathjax.git
Then create a self-rendering document, say, euler.html
likethis:
<!DOCTYPE html>
<script>
window.texme = {
markdownURL: 'marked/marked.min.js',
MathJaxURL: 'mathjax/es5/tex-mml-chtml.js'
}
</script>
<script src="texme/texme.min.js"></script>
<textarea>
# Euler's Identity
In mathematics, **Euler's identity** is the equality
$$ e^{i \pi} + 1 = 0. $$
## Explanation
Euler's identity is a special case of Euler's formula from complex
analysis, which states that for any real number $ x $,
$$ e^{ix} = \cos x + i \sin x. $$
</textarea>
Now, open euler.html
with a web browser and it shouldself-render fine. All resources will be loaded from the localdisk.
Now test euler.html
by serving it via a web server. AssumingPython 3 is installed, here is one really easy way to test it:
python3 -m http.server
Then open https://localhost:8000/euler.html
using a web server.The network tab in the browser's developer tools should show thatall resources are loaded from the same web server and no requeststo any other server are made.
TeXMe provides a special LaTeX-like environment named md
. This is themarkdown priority environment. We will see what this term means in thenext section. Let us first see what this environment does by looking ata few examples of when this special environment can be useful.
TeXMe introduces the special purpose md
environment to protectportions of Markdown content from being interpreted as LaTeX. In mostdocuments, the use of this environment is not required. Thisenvironment is useful only in a handful of scenarios where a Markdownelement like code span, code block, link, image, etc. may containcontent with LaTeX delimiters that may get interpreted as LaTeX by TeXMethereby leading to a broken rendering of the Markdown element. Thisenvironment protects the content of one or more Markdown elements frombeing interpreted as LaTeX. Let us see a few examples in the next twosubsections.
The md
environment is useful when Markdown code spans or code blockscontain LaTeX delimiters. This environment prevents the content ofMarkdown code spans and code blocks from being interpreted as LaTeX.Here is an example:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Using Variables
To expand a variable in shell script, prefix the variable name with a
dollar sign. For example:
```
foo=hello
echo $foo
```
The variable `$foo` is substituted with its value, if any, after the
expansion. In the above example, `$foo` expands to the string `hello`,
so the output looks like this:
```
hello
```
The above code fails to render as expected because the TeXMe tokenizerparses out everything between $foo
and `$
(inclusive)and interprets it as possible LaTeX code and prevents the Markdownparser from seeing it. As a result, the Markdown parser does not see thetriple backticks (```
) just after echo $foo
and the documentgets rendered in an unexpected manner. Here is how the output looks:shell-script-unprotected.html.
A rendering issue like this can be prevented with the use of themarkdown priority environment like this:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Using Variables
To expand a variable in shell script, prefix the variable name with a
dollar sign. For example:
\begin{md}
```
foo=hello
echo $foo
```
\end{md}
The variable \begin{md}`$foo`\end{md} is substituted with its value, if
any, after the expansion. In the above example, \begin{md}`$foo`\end{md}
expands to `hello`, so the output looks like this:
```
hello
```
The \begin{md}
and \end{md}
delimiters create a markdown priorityenvironment that prevents TeXMe from interpreting anything within it asLaTeX. Here is how the output looks now:shell-script-protected.html.
Here is another example that shows how rendering can break when LaTeXdelimiter is found in a Markdown element such as within imagedescription and how the usage of the md
environment can fix it. Hereis an example:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Metasyntactic Variable
![Screenshot of variable $foo assigned and echoed in shell][1]
The screenshot above shows an example usage of a metasyntactic variable
`$foo` in an interactive shell session.
[1]: https://i.imgur.com/iQx46hd.png
The above input fails to render as expected because the TeXMe tokenizerparses out everything between the first occurrence of $foo
within theimage description and the next occurrence of `$
(inclusive). As aresult, the Markdown parser does not see the closing bracket of theimage description and does not recognize the image element. This leadsto a broken rendering of the document. Here is how the output looks:img-alt-unprotected.html.
The md
environment can be used to fix the rendering like this:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Metasyntactic Variable
\begin{md}
![Screenshot of variable $foo assigned and echoed in shell][1]
\end{md}
The screenshot above shows an example usage of a metasyntactic variable
\begin{md}`$foo`\end{md} in an interactive shell session.
[1]: https://i.imgur.com/iQx46hd.png
Here is how the output looks now:img-alt-protected.html.
In this subsection, we dive a little deeper into what the md
environment is. First, we need to understand how TeXMe renders adocument. TeXMe performs the following steps while rendering a document:
At first, the tokenizer looks for anything that looks like LaTeX andmasks them, that is, it substitutes all LaTeX snippets in thecontent with mask literal. In case you are curious, the mask literalis ::MASK::
but this detail should not matter to you while usingTeXMe.
Then it feeds the masked input to Markdown parser. The Markdownparser cannot see any LaTeX code anymore because they are allmasked, so it cannot accidentally render any portion of the LaTeXcode as Markdown. The Markdown parser returns a rendered HTML.
The rendered HTML is then unmasked, that is, all mask literals inthe rendered HTML are substituted with the original LaTeXsnippets.
At this point, TeXMe rendering is complete. Now TeXMe invokesMathJax to render all LaTeX content in the HTML obtained fromthe previous step.
It is important to note that TeXMe does not implement a Markdown parserof its own. It relies on an existing popular and stable Markdownparser that conforms to the CommonMark specification and has stood thetest of time. TeXMe only parses out content within LaTeX delimiters andmasks it, so that the Markdown parser cannot see such content. As aresult of this, step 1 can be a problem when there are LaTeX delimiterslike $
, $$
, etc. within a Markdown code span/block. The TeXMetokenizer interprets the delimiter and the content after it as LaTeX ifit finds the corresponding closing delimiter too later in the document.This can break the Markdown rendering of the code span/block. An exampleof this was discussed in the previous section. This issue occurs becauseTeXMe parses out and masks the LaTeX snippet before invoking theMarkdown parser. The md
environment prevents TeXMe from looking forLaTeX content within the environment.
The md
environment ensures that anything within \begin{md}
and\end{md}
is not searched for LaTeX delimiters. Anything within thisenvironment is fed to the Markdown parser intact. This is why thisenvironment is known as the Markdown priority environment.
In the previous two subsections we saw how the Markdown priorityenvironment, that is, the md
environment is used and what it does butthat is not the entire story. TeXMe provides an unlimited number ofvariants of the md
environment. In fact, any environment name thatstarts with the string md
is a Markdown priority environment, that is,all of \begin{md*}
, \begin{md**}
, \begin{mdfoo}
, \begin{mdbar}
,etc. start Markdown priority environments provided the corresponding\end
commands also exist. The \end
command for a Markdown priorityenvironment must use the exact same environment name as the \begin
delimiter.
The availability of unlimited variants of the Markdown priorityenvironment is useful when we have a Markdown code span/block thatitself contains code with Markdown priority environment in it such asperhaps a code example that explains how TeXMe works. Consider thefollowing example:
<!DOCTYPE html><script src="https://cdn.jsdelivr.net/npm/texme@1.0.0"></script><textarea>
# Markdown Priority Environment
Here is an example usage of Markdown priority environment:
\begin{md*}
````
\begin{md}
```
foo=hello
echo $foo
```
\end{md}
````
\end{md*}
The above example shows how to protect \begin{md}`$`\end{md},
\begin{md*}`\begin{md}`\end{md*}, and \begin{md*}`\end{md}`\end{md*} in
a Markdown code block.
Here is the output:texme-code-protected.html.
If we start the Markdown priority environment with \begin{md}
, then wecannot have \end{md}
anywhere within the environment because the firstoccurrence of it would end the environment. That is why we use\begin{md*}
and \end{md*}
to create a Markdown priority environment.Now we can safely write \end{md}
within it.
In case you are wondering what the quadruple backticks are doing in theabove code example, it is a feature defined in the CommonMarkspecification. It creates a code block within which we can safely usetriple backticks. CommonMark allows us to start a code span/block withan arbitrary number of backticks such the code span/block may safelycontain consecutive backticks. To be precise a code span that startswith M backticks can safely contain N consecutive backticks as long as M≠ N. Similarly, a code block that starts with M backticks (M ≥ 3)can safely contain N consecutive backticks as long as M > N. All of thisis standard CommonMark and not something introduced by TeXMe. TeXMe onlyintroduces the special purpose md
environment and its unlimitedvariants.
This is free and open source software. You can use, copy, modify,merge, publish, distribute, sublicense, and/or sell copies of it,under the terms of the MIT License. See LICENSE.md for details.
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,express or implied. See LICENSE.md for details.
To report bugs, suggest improvements, or ask questions,create issues.