markdown-it-typst
v1.0.2
Published
Plugin to transform Typst code to SVG image for markdown-it markdown parser.
Downloads
9
Readme
markdown-it-typst
A simple typst.ts
wrapper that adds Typst support to markdown-it
.
WARNING: It's NOT recommended to run this plugin on browser side, as it is not optimized for tree-shaking. (See typst.ts
Documentation) However, utilizing the browser-side version of typst.ts
is still possible, any PRs regarding this are welcome.
Usage
npm install markdown-it-typst
import MarkdownIt from "markdown-it";
import MarkdownItTypst from "markdown-it-typst";
const md = new MarkdownIt().use(MarkdownItTypst);
const code = `
\`\`\`typst
#set text(font: "New Computer Modern")
Let $a$, $b$, and $c$ be the side
lengths of right-angled triangle.
Then, we know that:
$ a^2 + b^2 = c^2 $
Prove by induction:
$ sum_(k=1)^n k = (n(n+1)) / 2 $
\`\`\`
`;
const html = md.render(code);
console.log(html);
// Output:
//
// <div class="typst">
// <svg class="typst-doc" [...]>
// [...]
// </svg>
// </div>
The code above will render the following web page (Without additional styling):
Features
Able to import packages:
**Normal** *Markdown* code :-) ```typst #import "@preview/cetz:0.2.2": canvas, draw, tree #canvas(length: 2.5cm, { import draw: * tree.tree( draw-node: (node, ..) => { if node.content == [] { return none } circle((), radius: .35, stroke: black) content((), [#node.content]) }, draw-edge: (from, to, pa, child) => { if child.content == [] { return none } tree.default-draw-edge(from, to, pa, child) }, ([15], ([13], [12], [14]), ([17], [16], ([18], [], [18]))) ) }) ```
Able to import external files:
```typst #figure( image("./images/cat.png", width: 200pt), caption: [`/bin/cat`], ) ```
Options
Default options:
const md = new MarkdownIt().use(MarkdownItTypst, {
identifier: "typst",
typstWrapper: (code: string) =>
"#set page(width: auto, height: auto, margin: 5pt)\n" +
"#set text(size: 18pt)\n" +
code,
svgWrapper: (svg: string) => '<div class="typst">\n' + svg + "\n</div>",
});
identifier
- Type:
string | string[]
- Default:
"typst"
The language identifier(s) of the Typst code block. Only code blocks with the specified identifiers will be processed.
typstWrapper
- Type:
(code: string) => string
- Default:
(code: string) => "#set page(width: auto, height: auto, margin: 5pt)\n#set text(size: 18pt)\n" + code
Typst code will be wrapped with this function before being compiled.
svgWrapper
- Type:
(svg: string) => string
- Default:
(svg: string) => '<div class="typst">\n' + svg + "\n</div>"
The SVG output will be wrapped with this function during rendering.
Examples
The probably most handy application is to render CeTZ graphs in Markdown:
const md = new MarkdownIt().use(MarkdownItTypst, {
typstWrapper: (code: string) =>
"#set page(width: auto, height: auto, margin: 5pt)\n" +
'#import "@preview/cetz:0.2.2": canvas, draw, vector, matrix\n' +
"#canvas(length: 1cm, {\n" +
" import draw: *\n" +
code +
"})",
identifier: "cetz",
});
Electromagnetic waves are **transverse** waves:
```cetz
// Code borrowed from CeTZ: https://typst.app/universe/package/cetz/
// Set up the transformation matrix
set-transform(matrix.transform-rotate-dir((1, 1, -1.3), (0, 1, .3)))
scale(x: 1.5, z: -1)
grid((0,-2), (8,2), stroke: gray + .5pt)
// Draw a sine wave on the xy plane
let wave(amplitude: 1, fill: none, phases: 2, scale: 8, samples: 100) = {
line(..(for x in range(0, samples + 1) {
let x = x / samples
let p = (2 * phases * calc.pi) * x
((x * scale, calc.sin(p) * amplitude),)
}), fill: fill)
let subdivs = 8
for phase in range(0, phases) {
let x = phase / phases
for div in range(1, subdivs + 1) {
let p = 2 * calc.pi * (div / subdivs)
let y = calc.sin(p) * amplitude
let x = x * scale + div / subdivs * scale / phases
line((x, 0), (x, y), stroke: rgb(0, 0, 0, 150) + .5pt)
}
}
}
group({
rotate(x: 90deg)
wave(amplitude: 1.6, fill: rgb(0, 0, 255, 50))
})
wave(amplitude: 1, fill: rgb(255, 0, 0, 50))
```
The option typstWrapper
can serve as a way to inject the necessary imports and setup code for typst. However, it may appear ugly to have such long code in the wrapper function. A better way it to utilize the #import
directive in the Typst code block:
const md = new MarkdownIt().use(MarkdownItTypst, {
typstWrapper: (code: string) =>
'#import("./preset.typ")\n' + code,
});