md2any 0.3.0

Markdown → PowerPoint, OpenDocument Impress, PDF, Word, Writer, HTML, SVG, and PNG. One markdown source, one small Rust binary.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
---
title: md2any
subtitle: One markdown source · eight output formats
author: md2any --help
date: built from the embedded HELP.md
theme: light
aspect: 16:9
---

# Quick start

## One command, eight formats

You wrote Markdown. md2any turns it into a polished deliverable — slides, documents, or PDF — without spawning Office, calling a JRE, or running a Python pipeline.

```bash
md2any talk.md                 # → talk.pptx (PowerPoint)
md2any talk.md -o talk.odp     # → talk.odp  (LibreOffice Impress)
md2any talk.md -o talk.pdf     # → talk.pdf  (PDF 1.7)
md2any talk.md -o talk.docx    # → talk.docx (Microsoft Word)
md2any talk.md -o talk.odt     # → talk.odt  (LibreOffice Writer)
md2any talk.md -o talk.html    # → talk.html (browser deck)
md2any talk.md --format svg -o talk-svg/   # → one SVG per slide
md2any talk.md --format png -o talk-png/   # → one PNG per slide
```

One Rust binary. No runtime dependencies. Cross-platform.

## What md2any can do now

md2any is built for the boring part of technical publishing: one source file, many artifacts, repeatable in CI.

| Area | Capabilities |
|------|--------------|
| Outputs | PPTX, ODP, PDF, DOCX, ODT, standalone HTML, SVG slide images, PNG slide images |
| Slides | Section dividers, four deck layouts, light/dark themes, custom page sizes, transitions, TOC slides, presenter notes |
| Documents | Report-style DOCX/ODT with title page, contents, headers/footers, styled code/tables, image captions, notes appendices |
| Pagination | Smart continuation splitting for paragraphs, lists, code, columns, and tables; density control with `--break-fill` |
| Tables | Auto table fitting, column-group splitting, key-column repeat, portrait transposition |
| Code | Dark-by-default code blocks, independent code palette, 40+ syntax tags, filename captions, file/range includes, automatic line numbers, landscape two-up code flow |
| Math | Native Unicode math, generated display SVG math, and full-page markup math with selectable PDF text |
| Images | Local, remote, SVG rasterisation, remote cache/retry, full-page image slides, background images, width hints |
| Fonts | Bundled DejaVu PDF fonts, custom PDF fonts, fallback fonts, CJK opt-in, glyph audit |
| Workflow | `--watch`, live `--serve` preview in PDF/HTML/SVG/PNG, linting, outline, IR JSON, render-plan JSON |

The design goal is not to be Pandoc, Quarto, TeX, or a presentation GUI. It is a deterministic artifact generator that keeps the common deck/document job small enough to ship as one binary.

## Self-documenting

This deck is the embedded user manual. Regenerate it in any format, any layout, any theme:

```bash
md2any --help-pptx                       # this deck → md2any-help.pptx
md2any --help-pdf --theme dark           # dark PDF
md2any --help-odp --layout studio        # studio layout, ODP
md2any --help-docx                       # → Word document
md2any --help-odt                        # → LibreOffice Writer document
md2any --help-html                       # → standalone browser deck
md2any --help-svg -o manual-svg/          # → one SVG per manual slide
md2any --help-png -o manual-png/          # → one PNG per manual slide
md2any --help-md > HELP.md               # raw markdown source
```

Every `--help-*` flag respects every other flag.

# Anatomy of a deck

## Pagination rules

md2any turns Markdown headings into slides. Memorize three rules:

- The first `# H1` (or the front-matter `title`) becomes the **title slide**
- Every subsequent `# H1` becomes a **section divider**
- Every `## H2` starts a **content slide**
- A horizontal rule `---` forces a slide break without changing the title
- `### H3` and deeper render as inline headings on the current slide

Long content auto-paginates into `(cont.)` slides. Lists with more than 12 items wrap into two columns automatically (except in portrait mode). The default `--break-mode smart` splits overlong paragraphs, lists, code, tables, and columns at readable boundaries; use `--break-mode simple` for conservative block-level splitting or `--break-mode off` to disable automatic continuation splitting. `--break-fill PCT` controls density before a break: lower than 100 creates more, airier slides; higher values pack tighter. Pagination is skipped in DOCX/ODT — those formats flow continuously and let the consumer paginate.

## Front matter

Put YAML between `---` fences at the top of the file.

```yaml
---
title: My Talk
subtitle: A subtitle for the title slide
author: Your Name
date: auto              # or 2026-05-23, or "today"
theme: light            # light | dark
aspect: 16:9            # see "Aspect ratios" below for all presets,
                        # or `WxH[unit]` e.g. 1920x1080, 300x200mm, 13.3x7.5in
layout: clean           # clean | studio | frame | bold
math: unicode           # unicode | source | svg
math_scale: 1.0         # generated SVG display math scale
math_block_align: center # left | center | right
math_max_height: 180    # generated display math height cap
math_macros:
  '\RR': '\mathbb{R}'   # exact math substitutions before rendering
doc_style: report       # plain | report | handout | speaker-notes
break_mode: smart       # smart | simple | off
break_fill: 100         # 50-120; lower breaks earlier, higher packs tighter
table_fit: auto         # auto | split | transpose | off
code_theme: dark        # dark | light | match; default is dark, independent of theme
code_columns: single    # single | auto | two-up; landscape code flow
font: Inter             # any installed font (PPTX/ODP/DOCX/ODT)
logo: brand.png         # rendered in slide footer
toc: true               # inject a Contents slide after the title
transition: fade        # none | fade | push | wipe | cover | split
transition_duration: 0.6  # seconds
direction: ltr          # ltr | rtl
---
```

Every key is optional. CLI flags override front matter; front matter overrides defaults.

# Markdown reference

## Inline formatting

The usual:

- `**bold**` → **bold**
- `*italic*` → *italic*
- `` `inline code` `` → `inline code`
- `~~strikethrough~~` → ~~strikethrough~~
- `[link text](url)` → [link text](https://example.com) — **clickable in every format**

All eight output formats render these natively — no raw-HTML workaround, no extension.

## Lists

Nested up to nine levels. Numbered and bulleted lists are independent.

- First level item
- Second top-level item
  - Nested item
  - Another nested item
    - Triple-nested
- Back to level 1

```markdown
1. Step one
2. Step two
   1. Sub-step
   2. Another sub-step
3. Step three
```

If a list has more than 12 items, md2any auto-flows it into two columns (slide output only).

## Code blocks

Fenced code blocks pick up syntax highlighting from the language tag. Code blocks default to a dark editor-style palette even when the deck uses `theme: light`; use `--code-theme light` for light code blocks or `--code-theme match` to make code follow the main theme.

40+ language tags built in:

- Mainstream: `rust`, `python`, `js` / `ts` / `jsx` / `tsx`, `go`, `c` / `cpp`, `java`, `kotlin`, `scala`, `csharp`, `ruby`, `bash`, `powershell`, `sql`
- Functional / retro: `haskell`, `bcpl`, `bf`
- Data / config: `json`, `yaml`, `toml`, `ini`, `env`, `properties`, `terraform` / `hcl`, `dockerfile`
- Web / API: `html`, `xml`, `css`, `vue`, `svelte`, `astro`, `graphql`, `http`, `diff`, `markdown`
- Mainframe / IBM i: `cobol`, `jcl`, `rexx`, `pl1` / `pli` / `plx`, `hlasm`, `db2`, `rpg` / `rpg2` / `rpg3`, `rpgle` / `rpgfree`, `cl` / `clle`

## Code blocks (continued)

A bare fence picks the language only:

````
```rust
fn main() { println!("hi"); }
```
````

Add a filename after the language and md2any renders a header bar:

````
```rust src/main.rs
fn main() { println!("hi"); }
```
````

Code blocks longer than five lines get line numbers automatically. When a long
code block is split across continuation slides, numbering continues from the
original source line instead of restarting at 1.

Code theme is independent of the main deck theme:

```bash
md2any talk.md --code-theme dark   # default
md2any talk.md --code-theme light
md2any talk.md --code-theme match  # old behavior: follow --theme
```

Landscape code can flow left/right on one slide:

```bash
md2any talk.md --code-columns single  # default
md2any talk.md --code-columns auto    # only when a block is long and readable
md2any talk.md --code-columns two-up  # force eligible landscape blocks
```

Per-fence overrides use `columns=1`, `columns=auto`, or `columns=2`:

````
```rust columns=2 title="one method"
fn parse(input: &str) {
    // left column continues into right column with line numbers preserved
}
```
````

## Code — two-up / n-up

For code, n-up currently means one-up or two-up. Use `columns=2` when a long, narrow listing reads better as left/right columns on a landscape slide. `columns=auto` lets md2any choose two-up only when the block is long enough and not too wide.

```rust columns=2 title="src/window.rs" start=42
pub fn visible_window(items: &[Item], selected: usize, height: usize) -> Range<usize> {
    let height = height.max(1);
    let len = items.len();
    if len <= height {
        return 0..len;
    }
    let half = height / 2;
    let mut start = selected.saturating_sub(half);
    if start + height > len {
        start = len - height;
    }
    let end = (start + height).min(len);
    start..end
}

pub fn clamp_selection(selected: usize, len: usize) -> usize {
    selected.min(len.saturating_sub(1))
}
```

Two-up is landscape-only. In portrait aspects, md2any keeps code one-up so the columns do not become unreadable. Three-up and wider code layouts are intentionally not exposed; code usually turns into eye chart territory before it becomes useful.

## Tables

GitHub-flavored Markdown tables. Banded rows, accent-colored header.

| Column | Type | Notes |
|--------|------|-------|
| name   | text | first column |
| size   | int  | second column |
| active | bool | third column |

Alignment hints (`:--`, `:-:`, `--:`) parse but render as left for now.

## Side-by-side columns

Put `:::` on a line by itself to split a slide into two columns:

```markdown
## Pros and cons

Left side content goes here. Bullets, paragraphs, code, all work.

:::

Right side content. Independently paginated.
```

In slide output both columns scale to fit. In document output (DOCX/ODT) columns flatten into back-to-back blocks.

## Blockquotes

Render with a vertical accent bar and italic body text.

> The best presentation tool is the one that gets out of your way.
>
> Plain text in, polished slides out. That's the whole product.

## Math

md2any has native math support. It is deliberately not TeX: no TeX runtime, no MathJax, no shelling out, no bundled equation renderer. The implementation is a small deterministic parser/layout engine aimed at talks, technical notes, and CI-friendly output.

There are three normal math modes:

- `--math unicode` (default) translates inline `$...$` and display `$$...$$` spans into readable Unicode at parse time.
- `--math source` leaves `$...$` and `$$...$$` untouched for a downstream tool, reviewer, or source-preserving workflow.
- `--math svg` lays out display `$$...$$` blocks with md2any's built-in box model and embeds generated SVG image data. Inline `$...$` remains source text in this mode.

`--math svg` understands multi-line display blocks, stacked fractions, square-root bars, positioned scripts, scalable delimiters, simple matrices, arrays, `cases`, and aligned equations. The generated SVG passes through the normal image pipeline for PPTX, ODP, PDF, HTML, SVG, PNG, DOCX, and ODT.

Generated display math can be tuned without adding a TeX runtime:

```bash
md2any talk.md --math svg --math-scale 0.9 --math-block-align left --math-max-height 160
```

The same controls are available in front matter as `math_scale`, `math_block_align`, and `math_max_height`.

For repeated notation, define exact substitutions in front matter. Use single quotes around TeX-style keys so YAML does not treat backslashes as escapes:

```yaml
math_macros:
  '\RR': '\mathbb{R}'
  '\NN': '\mathbb{N}'
```

```markdown
Einstein wrote $E = mc^2$.

$$\sum_{i=1}^{n} i = \frac{n(n+1)}{2}$$
```

The next slides walk through every construct md2any understands, with source on the left and what it renders to on the right. `--check` reports unsupported rich constructs in the default Unicode mode before they silently degrade.

## Math — full-page markup

For dense formula pages, use `text-full` with a fenced `math` block. This is the path for "make this A4 page a formula, not a normal slide":

````markdown
---
aspect: a4
break_mode: off
---

<!-- layout: text-full -->

```math
\mathcal{L}_{SM} = -\frac{1}{2}\partial_\nu g^a_\mu\partial^\nu g^{a\mu}
-g_s f^{abc}\partial_\mu g^a_\nu g^{b\mu}g^{c\nu}
```
````

PDF renders this as selectable positioned text plus vector strokes for bars, radicals, and delimiters. SVG/PNG render the same positioned layout. It is useful for posters, paper-sized technical pages, and stress-test equations such as the Standard Model Lagrangian.

This is still md2any-native math, not TeX typography. Expect readable deck-quality layout, not publication-grade mathematical typesetting.

## Math — Greek letters

| Source       | Renders as | Source       | Renders as |
|--------------|------------|--------------|------------|
| `$\alpha$`   | $\alpha$   | `$\nu$`      | $\nu$      |
| `$\beta$`    | $\beta$    | `$\xi$`      | $\xi$      |
| `$\gamma$`   | $\gamma$   | `$\pi$`      | $\pi$      |
| `$\delta$`   | $\delta$   | `$\rho$`     | $\rho$     |
| `$\epsilon$` | $\epsilon$ | `$\sigma$`   | $\sigma$   |
| `$\zeta$`    | $\zeta$    | `$\tau$`     | $\tau$     |
| `$\eta$`     | $\eta$     | `$\upsilon$` | $\upsilon$ |
| `$\theta$`   | $\theta$   | `$\phi$`     | $\phi$     |
| `$\iota$`    | $\iota$    | `$\chi$`     | $\chi$     |
| `$\kappa$`   | $\kappa$   | `$\psi$`     | $\psi$     |
| `$\lambda$`  | $\lambda$  | `$\omega$`   | $\omega$   |
| `$\mu$`      | $\mu$      | `$\aleph$`   | $\aleph$   |

Uppercase forms work the same way: `$\Gamma$` → $\Gamma$, `$\Delta$` → $\Delta$, `$\Theta$` → $\Theta$, `$\Lambda$` → $\Lambda$, `$\Xi$` → $\Xi$, `$\Pi$` → $\Pi$, `$\Sigma$` → $\Sigma$, `$\Phi$` → $\Phi$, `$\Psi$` → $\Psi$, `$\Omega$` → $\Omega$.

## Math — big operators

| Source         | Renders as     |
|----------------|----------------|
| `$\sum$`       | $\sum$         |
| `$\prod$`      | $\prod$        |
| `$\int$`       | $\int$         |
| `$\oint$`      | $\oint$        |
| `$\bigcup$`    | $\bigcup$      |
| `$\bigcap$`    | $\bigcap$      |
| `$\sum_{i=1}^{n} i$` | $\sum_{i=1}^{n} i$ |
| `$\int_a^b f(x) dx$` | $\int_a^b f(x) dx$ |
| `$\prod_{k=1}^{n} k$` | $\prod_{k=1}^{n} k$ |

Subscripts and superscripts after a big operator render as small adjacent glyphs. Stacked above/below limits are outside md2any's small math layout model.

## Math — relations

| Source       | Renders as | Source        | Renders as  |
|--------------|------------|---------------|-------------|
| `$\leq$`     | $\leq$     | `$\equiv$`    | $\equiv$    |
| `$\geq$`     | $\geq$     | `$\sim$`      | $\sim$      |
| `$\neq$`     | $\neq$     | `$\simeq$`    | $\simeq$    |
| `$\approx$`  | $\approx$  | `$\propto$`   | $\propto$   |

```markdown
$a \leq b \neq c \approx d \propto e$
```

Renders as: $a \leq b \neq c \approx d \propto e$

## Math — arrows

| Source              | Renders as          |
|---------------------|---------------------|
| `$\to$`             | $\to$               |
| `$\rightarrow$`     | $\rightarrow$       |
| `$\leftarrow$`      | $\leftarrow$        |
| `$\Rightarrow$`     | $\Rightarrow$       |
| `$\Leftarrow$`      | $\Leftarrow$        |
| `$\leftrightarrow$` | $\leftrightarrow$   |
| `$\Leftrightarrow$` | $\Leftrightarrow$   |
| `$\mapsto$`         | $\mapsto$           |

Use the capitalised forms (`\Rightarrow`, `\Leftrightarrow`) for logical implication; the lowercase forms are for set membership / function notation.

## Math — set and logic

| Source        | Renders as | Source         | Renders as  |
|---------------|------------|----------------|-------------|
| `$\in$`       | $\in$      | `$\forall$`    | $\forall$   |
| `$\notin$`    | $\notin$   | `$\exists$`    | $\exists$   |
| `$\subset$`   | $\subset$  | `$\nexists$`   | $\nexists$  |
| `$\subseteq$` | $\subseteq$| `$\emptyset$`  | $\emptyset$ |
| `$\supset$`   | $\supset$  | `$\land$`      | $\land$     |
| `$\supseteq$` | $\supseteq$| `$\lor$`       | $\lor$      |
| `$\cup$`      | $\cup$     | `$\lnot$`      | $\lnot$     |
| `$\cap$`      | $\cap$     | `$\setminus$`  | $\setminus$ |

```markdown
$\forall x \in \mathbb{N}, \exists y : y > x$
```

Renders as: $\forall x \in \mathbb{N}, \exists y : y > x$

## Math — super and subscripts

| Source            | Renders as        |
|-------------------|-------------------|
| `$x^2$`           | $x^2$             |
| `$a_i$`           | $a_i$             |
| `$x^{n+1}$`       | $x^{n+1}$         |
| `$a_{ij}$`        | $a_{ij}$          |
| `$a_{ij}^{k+1}$`  | $a_{ij}^{k+1}$    |
| `$e^{i\pi}$`      | $e^{i\pi}$        |
| `$\sigma_x$`      | $\sigma_x$        |

A single character following `^` or `_` is the superscript / subscript; for multi-character groups wrap them in `{…}`.

## Math — fractions, roots, binomials

| Source                | Renders as            |
|-----------------------|-----------------------|
| `$\frac{a}{b}$`       | $\frac{a}{b}$         |
| `$\frac{1}{1-r}$`     | $\frac{1}{1-r}$       |
| `$\sqrt{x}$`          | $\sqrt{x}$            |
| `$\sqrt{a^2 + b^2}$`  | $\sqrt{a^2 + b^2}$    |
| `$\binom{n}{k}$`      | $\binom{n}{k}$        |

```markdown
$\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$
```

Renders as: $\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$

In `--math unicode` mode, fractions and roots render inline as readable Unicode/ASCII. In `--math svg` display blocks, the built-in layout engine draws a real fraction bar and radical overbar.

## Math — accents, text, and alphabets

| Source                       | Renders as                    |
|------------------------------|-------------------------------|
| `$\vec{x}$`                  | $\vec{x}$                     |
| `$\bar{x}$`                  | $\bar{x}$                     |
| `$\hat{\theta}$`             | $\hat{\theta}$                |
| `$\tilde{A}$`                | $\tilde{A}$                   |
| `$\dot{x}$`                  | $\dot{x}$                     |
| `$\ddot{x}$`                 | $\ddot{x}$                    |
| `$\overline{AB}$`            | $\overline{AB}$               |
| `$\mathrm{rank}(A)$`         | $\mathrm{rank}(A)$            |
| `$\text{score} = 1$`         | $\text{score} = 1$            |
| `$\operatorname*{argmax}_x$` | $\operatorname*{argmax}_x$    |
| `$\mathbb{R}^n$`             | $\mathbb{R}^n$                |
| `$\mathcal{F}$`              | $\mathcal{F}$                 |

Accents use Unicode combining marks, so they are readable and selectable but not TeX-positioned. `\mathbb{...}` maps common uppercase sets such as `\mathbb{N}`, `\mathbb{Z}`, `\mathbb{Q}`, `\mathbb{R}`, and `\mathbb{C}` to their blackboard Unicode forms. `\mathcal{...}` maps uppercase letters where Unicode has script codepoints.

## Math — operator names

LaTeX `\log` / `\sin` / etc. don't exist as Unicode characters; they're typeset as roman text inside math. md2any preserves them as plain ASCII with a trailing space so multiplication doesn't merge them with their argument.

| Source             | Renders as           |
|--------------------|----------------------|
| `$\log n$`         | $\log n$             |
| `$\ln x$`          | $\ln x$              |
| `$\sin \theta$`    | $\sin \theta$        |
| `$\cos \theta$`    | $\cos \theta$        |
| `$\tan \theta$`    | $\tan \theta$        |
| `$\max(a, b)$`     | $\max(a, b)$         |
| `$\min(a, b)$`     | $\min(a, b)$         |
| `$\lim_{x \to 0}$` | $\lim_{x \to 0}$     |
| `$\exp(x)$`        | $\exp(x)$            |
| `$\det A$`         | $\det A$             |
| `$\gcd(a, b)$`     | $\gcd(a, b)$         |

Also recognised: `\sec` `\csc` `\cot` `\sinh` `\cosh` `\tanh` `\arcsin` `\arccos` `\arctan` `\lg` `\sup` `\inf` `\argmax` `\argmin` `\rank` `\trace` `\tr` `\span`.

## Math — delimiters and spacing

In `--math unicode`, delimiter sizing macros collapse to readable plain delimiters. In `--math svg`, `\left...\right` pairs around fractions, matrices, arrays, and cases use drawn scalable delimiters so tall content is bracketed cleanly. `\big` / `\Big` / `\bigg` / `\Bigg` still act as lightweight delimiter hints rather than full TeX sizing commands.

| Source                          | Renders as                      |
|---------------------------------|---------------------------------|
| `$\left( x + y \right)$`        | $\left( x + y \right)$          |
| `$\big[ a, b \big]$`            | $\big[ a, b \big]$              |
| `$\Big\| \vec{v} \Big\|$`       | $\Big| \vec{v} \Big|$           |

Spacing macros map to ASCII space approximations: `\quad` → two spaces, `\qquad` → four, `\,` / `\:` / `\;` → thin space, `\!` → no-op.

## Math — dots and ellipses

| Source         | Renders as |
|----------------|------------|
| `$\ldots$`     | $\ldots$   |
| `$\cdots$`     | $\cdots$   |
| `$\vdots$`     | $\vdots$   |
| `$\ddots$`     | $\ddots$   |

```markdown
$x_1, x_2, \ldots, x_n$
$x_1 + x_2 + \cdots + x_n$
```

Render as: $x_1, x_2, \ldots, x_n$ and $x_1 + x_2 + \cdots + x_n$.

## Math — what md2any is *not*

The default Unicode math support is intentionally shallow. If you need readable multi-line display math, stacked fractions, radical bars, scalable delimiters, simple matrices/arrays, `cases`, or aligned equations, use `--math svg`. If you need a full-page formula with selectable PDF text, use `<!-- layout: text-full -->` with a fenced `math` block.

- **No TeX engine** — md2any does not run TeX, embed TeX, require TeX, or promise TeX-compatible spacing.
- **No publication-grade equation typography** — the built-in box model is good enough for talk decks and technical pages, not a replacement for a dedicated mathematical typesetting system.
- **No equation numbering** — there is no `\label` / `\ref` mechanism.
- **Copy/paste is best-effort for positioned math** — PDF text remains selectable via `/ToUnicode`, but a reader may paste positioned superscripts/fractions in geometric order rather than source order.

Everything *not* on that list works, and what works is enough for typical talk-deck math: equations, summations, integrals, set notation, predicate logic, accents, text labels, blackboard sets, simple rich display blocks, and dense A4 formula pages.

## Math — copy-paste from PDF

PDF text is copy-pasteable. md2any writes a `/ToUnicode` CMap with every embedded font, so selecting a formula in your PDF reader gives you back real Unicode characters — not glyph indices, not Latin substitutes.

Try it: open the manual PDF, select `∑ᵢ₌₁ⁿ xᵢ²` from any math slide, paste somewhere. You'll get the actual Unicode characters back.

This works for every glyph in every face: Greek, math operators, sub/superscripts, the CJK fallback if you passed `--cjk`, the line-drawing characters in the Unicode coverage slide.

Full-page `math` fences use many positioned text runs so superscripts, subscripts, and fraction parts sit where they should visually. The glyphs remain selectable, but PDF readers may paste them in geometric order rather than the original source order.

## Diagrams

Code fences with `dot`, `graphviz`, `mermaid`, or `plantuml` shell out to the matching CLI tool if it's on `$PATH` and embed the rendered PNG. If the tool isn't installed, the source stays as a regular code block.

````
```dot
digraph G {
  rankdir=LR;
  Client -> Proxy -> Database;
}
```
````

## Footnotes

Markdown footnotes (`[^id]`) render as superscript ¹²³ in the body, with definitions collected at the bottom of the slide where they were referenced.

```markdown
Rust was first released in 2015[^rust].

[^rust]: Originally a personal project by Graydon Hoare at Mozilla.
```

## Horizontal rules

A line containing just `---` forces a slide break while keeping the current section title. Use it for long sections that need to split across slides without introducing a new H2.

## Images

Standard markdown image syntax works in every output format:

```markdown
![A diagram](diagrams/architecture.png)
![Hero shot](https://example.com/hero.jpg)
![Logo](brand/logo.svg)
```

Three sources, one syntax:

- **Local PNG / JPEG** — resolved relative to the markdown file, embedded as-is.
- **Remote URL** (`http://` or `https://`) — fetched at build time with a 10 s timeout, capped at 20 MB per image, and cached after a successful download. The default cache location follows the host OS convention: `%LOCALAPPDATA%` on Windows, `~/Library/Caches` on macOS, and `$XDG_CACHE_HOME` / `~/.cache` on Linux and other Unix systems.
- **SVG** — rasterised to PNG via the bundled resvg engine at 192 DPI (2× retina), then embedded the same way as a regular raster image. Text in SVGs uses md2any's bundled DejaVu Sans family so renders look identical regardless of what's installed on the build machine.

Aspect ratio is preserved; the slide layout decides how much room each image gets.

### Sizing — `{width=N%}`

Append a Pandoc-style attribute to set the image to a fraction of the content column (slide formats only — DOCX/ODT defer to the consumer app):

```markdown
![Architecture](diagrams/arch.png){width=50%}
![Logo](brand/logo.png){width=20%}
```

Valid range is 1–100. Unrecognised attributes are ignored silently. Without the attribute, the image fills the content column at its native aspect ratio.

### Image layout directives

Use layout directives when an image should drive the slide geometry:

```markdown
## Architecture

<!-- layout: image-left -->

![diagram](arch.png)

Walks the request through the API gateway, then the service mesh,
then into the database tier. Each hop is observable via OpenTelemetry.
```

`<!-- layout: image-left -->` puts the image on the left and everything else on the right. `<!-- layout: image-right -->` does the opposite. The directive triggers only when the slide has exactly one image; otherwise it's ignored.

For a page that is itself an image, use `<!-- layout: image-full -->` on a slide with exactly one image. Slide renderers skip titles, rails, sidebars, and normal content image caps, then fit the image to the full page without distorting it. This is useful for source-image pages, posters, scanned handouts, or A4/Letter fixtures.

For a page that should remain selectable text, use `<!-- layout: text-full -->` on a slide with exactly one fenced code block. Slide renderers skip titles, rails, and sidebars, then fit the block to the full page.

- Fenced blocks tagged `text`, `rust`, `python`, and so on render as fitted text/code.
- A fenced block tagged `math` uses md2any's math layout engine: PDF gets selectable positioned text plus vector fraction/radical/delimiter strokes, and SVG/PNG get the same visual layout.

This is useful for dense code listings, source excerpts, formula pages, posters, and A4/Letter technical fixtures where keeping text selectable matters.

Remote-image cache controls:

```bash
md2any talk.md -o talk.pdf
md2any talk.md --remote-image-cache ./.md2any-cache -o talk.pdf
md2any talk.md --no-remote-image-cache -o talk.pdf
md2any talk.md --remote-image-user-agent "my-build/1.0" -o talk.pdf
```

Remote fetches retry transient failures (HTTP 408 / 429 / 500 / 502 / 503 / 504, network errors) up to three times with capped exponential backoff (max 30 s per wait), honouring `Retry-After` in both delta-seconds and HTTP-date forms. If your binary was compiled without the `remote-images` feature, `http://` and `https://` image references fail with a clear error; local images still work.

**On failure: placeholder instead of abort.** If an image can't be loaded — network failure, 404, garbage body, file missing, payload over the 20 MB cap, broken SVG — md2any prints a one-line stderr warning naming the source and the reason, then substitutes a red "Image failed to load" placeholder that includes the URL and error text. The render completes; you ship a deck where every missing-image slot is visibly flagged rather than discovering the failure when a viewer opens the file. CI pipelines can grep stderr for `warning: image failed` to surface the issue without failing the build.

**Cache retention.** Remote images are fetched once and reused on every subsequent render — there's no expiry and no conditional `If-Modified-Since` / `ETag` round-trip. If a remote image gets updated upstream, you'll keep seeing the old version until you delete the cache file. The default cache directory follows the platform convention; `md2any doctor` prints the resolved path. Clearing is just `rm -rf <cache-dir>/remote-images/`. The cap is 20 MB per image; oversized payloads trip the placeholder substitution above instead of silently truncating.

## Per-slide background

An HTML comment with `bg:` sets a full-bleed background image for the current slide.

```markdown
# Hero slide

<!-- bg: photos/hero.jpg -->

A statement.
```

Images load relative to the deck file. Background propagates through `(cont.)` continuation slides.

# Layouts

## Four ways to dress a deck

Same Markdown, different visual treatment:

- `clean` — minimal title underline + full-bleed content (default)
- `studio` — vertical accent rail, italic titles, big background numerals on sections
- `frame` — left sidebar carries deck title + slide number; content on the right
- `bold` — full-width accent block behind every title

Pick with `--layout NAME` or set `layout:` in front matter.

## When to use which

**clean** for talks where content should dominate. Minimal chrome.

**studio** for editorial / design-review decks. Italics, rails, big numerals. Looks serious without being heavy.

:::

**frame** for long training and onboarding decks where a persistent reference panel helps the audience.

**bold** for keynote-style events. Every section transition feels intentional. Maximum accent color.

# Themes

## Light vs dark

Two carefully-tuned palettes. Every layout supports both.

**Light theme**

White background, slate text, sky-blue accent. Reads well in bright rooms, prints cleanly.

```
--theme light    (default)
```

:::

**Dark theme**

Slate-900 background, frost-bright accent. Reads well on stage, easier on the eyes during long talks.

```
--theme dark
```

## Custom palettes

For brand-specific decks, override colors, fonts, and sizes with a YAML overlay. Pass it with `--theme-file PATH`. The overlay merges on top of whatever `--theme` selects (default `light`); only the keys you set are changed.

```bash
md2any talk.md --theme-file brand.yaml -o talk.pdf
```

Hex colours accept `#RRGGBB` or bare `RRGGBB`. Sizes are in hundredths of a typographic point (so `1800` = 18 pt). Font names must exist on the consumer's machine for PPTX/ODP/DOCX/ODT. PDF uses bundled DejaVu by default, but can load explicit TTF/OTF paths from CLI flags or from the theme file.

## --theme-file — colour keys

| Key            | Role                           | Light default | Dark default |
|----------------|--------------------------------|---------------|--------------|
| `bg`           | Slide background               | `#FFFFFF`     | `#0B1220`    |
| `title_color`  | Slide title text               | `#0F172A`     | `#F8FAFC`    |
| `body_color`   | Body / paragraph text          | `#334155`     | `#CBD5E1`    |
| `muted_color`  | Footer, captions, slide number | `#94A3B8`     | `#64748B`    |
| `accent`       | Underline bar, links, ✓ markers| `#0EA5E9`     | `#38BDF8`    |
| `accent_soft`  | Tag chips, code-fence label bg | `#E0F2FE`     | `#0C4A6E`    |
| `divider`      | Hairline rule under titles     | `#E2E8F0`     | `#1E293B`    |
| `code_bg`      | Code block fill                | `#F1F5F9`     | `#111A2E`    |
| `code_text`    | Code text (when not tokenised) | `#1E293B`     | `#E2E8F0`    |
| `code_accent`  | Inline `code` text             | `#0369A1`     | `#7DD3FC`    |
| `section_bg`   | Section-divider slide fill     | `#0F172A`     | `#0EA5E9`    |
| `section_text` | Section-divider slide text     | `#F8FAFC`     | `#FFFFFF`    |
| `link`         | Hyperlink text                 | `#0EA5E9`     | `#7DD3FC`    |
| `on_accent`    | Text drawn over `accent`       | `#FFFFFF`     | `#0B1220`    |

## --theme-file — fonts and sizes

| Key           | Role                                | Default (16:9)    |
|---------------|-------------------------------------|-------------------|
| `title_font`  | Title bar / heading typeface        | `Calibri Light`   |
| `body_font`   | Paragraph + list typeface           | `Calibri`         |
| `mono_font`   | Code / inline-code typeface         | `Consolas`        |
| `pdf_font`    | PDF sans/body TTF/OTF path          | bundled DejaVu    |
| `pdf_mono_font` | PDF mono/code TTF/OTF path        | bundled DejaVu Mono |
| `font_fallback` | PDF fallback path or list         | none              |
| `title_size`  | Title size, hundredths of pt        | `2800` (28 pt)    |
| `body_size`   | Body size, hundredths of pt         | `1800` (18 pt)    |
| `code_size`   | Code-block size, hundredths of pt   | `1500` (15 pt)    |
| `hero_size`   | Title-slide hero text, hundredths   | `5400` (54 pt)    |

Portrait aspects (9:16, A4, A5, Letter) ship slightly smaller defaults: `2400 / 1700 / 1400 / 4200`.

## --theme-file — syntax highlighting

Nested under a `syntax:` key. Each value is a hex colour applied to that token class across every supported language.

By default, fenced code blocks use the dark code palette regardless of the main `--theme`. Set `code_theme: light` or pass `--code-theme light` to force light code blocks; set `match` to make code follow the main theme. Explicit `code_bg`, `code_text`, `code_accent`, or `syntax:` values in a theme file still override the selected code palette.

| Key         | Role                              | Light default | Dark default |
|-------------|-----------------------------------|---------------|--------------|
| `keyword`   | `fn`, `class`, `SELECT`, etc.     | `#9333EA`     | `#C792EA`    |
| `string`    | String + char literals            | `#16A34A`     | `#C3E88D`    |
| `number`    | Numeric + boolean literals        | `#C2410C`     | `#FFCB6B`    |
| `comment`   | Line + block comments             | `#94A3B8`     | `#6B7B8E`    |
| `function`  | Function and method names         | `#2563EB`     | `#82AAFF`    |
| `type`      | Type names, capitalised idents    | `#0891B2`     | `#FFC777`    |
| `attribute` | Decorators, `#[derive]`, JSX attr | `#DC2626`     | `#F78C6C`    |

## --theme-file — full example

```yaml
# brand.yaml — a complete overlay touching every category
bg:           "#FFFCF7"
title_color:  "#0A0A23"
body_color:   "#1F2937"
muted_color:  "#9CA3AF"
accent:       "#FF6B35"
accent_soft:  "#FFE4D6"
divider:      "#E5E0D5"
code_bg:      "#F5F0E6"
code_text:    "#1F2937"
code_accent:  "#B8410B"
section_bg:   "#0A0A23"
section_text: "#FFFCF7"
link:         "#B8410B"
on_accent:    "#FFFCF7"

title_font: "Inter"
body_font:  "Inter"
mono_font:  "JetBrains Mono"
pdf_font: "fonts/Inter-Regular.ttf"
pdf_mono_font: "fonts/JetBrainsMono-Regular.ttf"
font_fallback:
  - "fonts/NotoSansMath-Regular.ttf"

title_size: 3000
body_size:  1900
code_size:  1500
hero_size:  5800

syntax:
  keyword:   "#D946EF"
  string:    "#15803D"
  number:    "#B8410B"
  comment:   "#9CA3AF"
  function:  "#1D4ED8"
  type:      "#0E7490"
  attribute: "#BE123C"
```

Set only the keys you want to change — anything omitted inherits from the underlying `--theme`. Theme fonts are names for PPTX/ODP/DOCX/ODT; PDF font keys are file paths and are embedded/subset in the output PDF. Relative PDF font paths in a theme file resolve next to that theme file.

# Aspect ratios

## Built-in presets

| Flag value         | Dimensions (mm)    | Dimensions (in)   | Use for                                  |
|--------------------|--------------------|-------------------|------------------------------------------|
| `16:9`             | 338.7 × 190.5 mm   | 13.33″ × 7.5″     | Modern projectors and screens (default)  |
| `4:3`              | 254 × 190.5 mm     | 10″ × 7.5″        | Legacy projectors                        |
| `9:16`             | 190.5 × 338.7 mm   | 7.5″ × 13.33″     | Vertical / phone-shaped                  |
| `a4`               | 210 × 297 mm       | 8.27″ × 11.69″    | A4 portrait (ISO 216)                    |
| `a4-landscape`     | 297 × 210 mm       | 11.69″ × 8.27″    | A4 landscape                             |
| `a3`               | 297 × 420 mm       | 11.69″ × 16.54″   | A3 portrait                              |
| `a5`               | 148 × 210 mm       | 5.83″ × 8.27″     | A5 portrait                              |
| `letter`           | 215.9 × 279.4 mm   | 8.5″ × 11″        | US Letter portrait (ANSI A)              |
| `letter-landscape` | 279.4 × 215.9 mm   | 11″ × 8.5″        | US Letter landscape                      |
| `legal`            | 215.9 × 355.6 mm   | 8.5″ × 14″        | US Legal                                 |
| `tabloid`          | 279.4 × 431.8 mm   | 11″ × 17″         | Tabloid / ANSI B                         |

## Custom dimensions

Anything that isn't a preset is parsed as `WIDTHxHEIGHT[unit]`. Plain numbers
with no suffix are pixels at 96 DPI.

```bash
md2any deck.md --aspect 1920x1080         # pixels at 96 DPI (default unit)
md2any deck.md --aspect 1920x1080px       # explicit px
md2any deck.md --aspect 300x200mm         # millimetres
md2any deck.md --aspect 30x20cm           # centimetres
md2any deck.md --aspect 13.33x7.5in       # inches
md2any deck.md --aspect 960x540pt         # PostScript points
md2any deck.md --aspect 12192000x6858000emu   # raw EMU
```

Decimal fractions are fine. Width and height can be in any order — md2any
treats `H > W` as portrait and adjusts typography accordingly.

Portrait layouts adjust typography automatically — smaller titles, narrower content area, single-column lists.

# Output formats

## Eight formats, one binary

| Format | Extension | Opens in | Editable? |
|--------|-----------|----------|-----------|
| PowerPoint | `.pptx` | PowerPoint, Keynote, LibreOffice Impress, Google Slides | yes |
| OpenDocument Impress | `.odp` | LibreOffice Impress, Keynote, Slides | yes |
| PDF | `.pdf` | Anything that opens PDFs | no |
| Microsoft Word | `.docx` | Word, LibreOffice Writer, Google Docs, Pages | yes |
| OpenDocument Writer | `.odt` | LibreOffice Writer, Word, Google Docs | yes |
| HTML | `.html` | Any modern browser | no |
| SVG images | directory | Any SVG viewer/browser | no |
| PNG images | directory | Any image viewer/browser | no |

All eight produced natively in pure Rust. No PDF library, no Office spawn, no external converter.

## Slides vs documents

The eight formats split into three families.

**Slide formats** — `pptx`, `odp`, `pdf`, `html` — paginate one slide per page using the deck's aspect ratio. Each `# H1` is a section divider; each `## H2` starts a new slide. Long content auto-flows into `(cont.)` slides.

Pagination controls are shared by PPTX, ODP, PDF, HTML, `--check`, `--outline`, and `--serve`:

- `--break-mode smart` (default) splits overlong paragraphs at sentence/clause/word boundaries, lists at item boundaries, code near blank/function lines, tables by row chunks, and columns independently.
- `--break-mode simple` keeps paragraphs, lists, and columns atomic, but still chunks very long code blocks and tables.
- `--break-mode off` disables automatic continuation splitting.
- `--break-fill PCT` sets the estimated fill target from 50 to 120 percent. Use values below 100 for more whitespace and values above 100 when you prefer tighter packing.
- `--table-fit auto` reshapes wide tables before pagination: compact portrait tables transpose, very wide tables split into column groups, and split tables repeat the first column as the key column. Use `split`, `transpose`, or `off` to force a specific strategy.

Code fences can include source snippets while preserving their real source line numbers:

````markdown
```rust file=src/main.rs#L20-L80 title="CLI parsing"
```
````

**Document formats** — `docx`, `odt` — flow continuously. The default `--doc-style report` produces a themed title page, contents, native headers/footers, section page breaks, styled tables/code, image captions, and flowing body content. Use `plain` for the older minimal flow, `handout` for slide labels, or `speaker-notes` to append a notes appendix.

**Image sequence formats** — `svg`, `png` — write one file per slide into the output directory (`slide-001.svg`, `slide-002.svg`, ...). Use these for docs screenshots, visual testing, social cards, and CI artifacts. PNG export rasterizes the same SVG through md2any's optional `svg` feature.

## When to use which

**PPTX** when someone needs to edit the slides. Native OOXML; opens everywhere.

**ODP** when you're all-in on LibreOffice or want smaller files (~⅓ the size of PPTX). Same render quality.

**PDF** when the deck needs to look identical on every machine. md2any
embeds bundled DejaVu fonts by default, or your supplied `--pdf-font` /
`--font-fallback` TTF/OTF files when configured, so output renders
identically in every reader regardless of installed fonts. Speaker notes are
dropped unless you render a notes PDF with `--with-notes`.

**DOCX** to hand someone the deck's contents as a Word document — for marking up, commenting, or printing as a handout.

**ODT** when your collaborator uses LibreOffice Writer, or when you want the smallest editable document format.

## Switching formats

The format auto-detects from the output extension:

```bash
md2any talk.md -o slides.pdf       # PDF
md2any talk.md -o slides.odp       # ODP
md2any talk.md -o slides.pptx      # PPTX
md2any talk.md -o paper.docx       # Word document
md2any talk.md -o paper.odt        # LibreOffice Writer
```

Or set it explicitly with `--format`:

```bash
md2any talk.md --format pdf
md2any talk.md --format docx --output /tmp/handout.docx
```

# Handout mode

## N-up printable PDF

`--handout N` (where N is 2, 4, or 6) produces an A4-portrait PDF with N slides per page. Use it to print a take-away after the talk.

```bash
md2any talk.md --handout 4 -o talk-handout.pdf
```

Slides become numbered thumbnails on the page. Layout, theme, and transitions remain untouched.

# Speaker package

`--speaker-package DIR` writes the common presentation bundle in one pass:
the editable deck, a presenter-notes PDF, a printable handout PDF, and a JSON
manifest. The deck defaults to PPTX; use `--format odp` or `--format pdf` when
you want the package deck in another slide format. `--handout 2|4|6` controls
the package handout density; the default is 4-up.

```bash
md2any talk.md --speaker-package release/
md2any talk.md --speaker-package release/ --format odp --handout 6
```

The manifest lists the source file, theme/layout/aspect, slide count, notes
count, generated artefacts, and image/logo assets referenced by the deck.

# Workflow

## Watch mode

`--watch` rebuilds the output every time the source changes. Pair with the file watcher in your editor for a live-rebuild loop:

```bash
md2any talk.md -o talk.pdf --watch
```

## Live preview server

`--serve` starts a tiny HTTP server on `localhost:8421` with auto-reload. Open the URL once, then just keep editing — the browser tab refreshes within ~500 ms of every save.

```bash
md2any talk.md --serve --port 9000
md2any talk.md --serve --serve-format html
md2any talk.md --serve --serve-format svg
md2any talk.md --serve --serve-format png
```

The default preview format is `pdf`. `--serve-format html` previews the standalone HTML deck, while `svg` and `png` use the same one-file-per-slide image renderer behind the regular image-sequence outputs.

No frontend dependencies. Pure std HTTP.

## Linting

`--check` parses and paginates without writing output, then prints warnings about likely visual issues — long titles, narrow tables, code that won't fit, lists that pile too high, missing image alt text, duplicated titles, weak theme contrast, oversized tables, and uneven speaker-note coverage. Exits with code 2 if any warnings.

```bash
md2any talk.md --check
```

Useful in CI to catch decks that will render poorly before you ship them.

## Diagnostics

`--emit-ir PATH` writes the post-parse/post-pagination slide tree as JSON. `--emit-plan PATH` writes the estimated render plan: page geometry, content box, pagination budget, block weights, continuation flags, and line metadata. `--trace-layout` prints a compact render-plan summary to stderr.

```bash
md2any talk.md --emit-ir /tmp/talk.ir.json --emit-plan /tmp/talk.plan.json
md2any talk.md --trace-layout --check
```

These diagnostics are meant for bug reports, CI artifacts, and renderer work. They are not available in `--serve` mode because the preview loop rebuilds continuously.

## Scaffolding

`md2any new talk.md` writes a starter deck with sensible front matter and a few example slides — front matter, title slide, section divider, content slide with a code block and a table.

```bash
md2any new keynote.md
md2any new keynote.md --force      # overwrite an existing file
```

## Multi-file decks

Pass multiple markdown files; they concatenate in order, with front matter from the first.

```bash
md2any intro.md body.md outro.md -o talk.pptx
```

Useful for very large decks where one file per section keeps editing manageable.

## Stdin

Pass `-` as the input to read from stdin:

```bash
cat draft.md | md2any - -o /tmp/preview.pdf
some-generator | md2any - --format docx > /tmp/auto.docx
```

# Command-line reference

## Every flag

```
md2any <INPUT...> [OPTIONS]
md2any new <PATH>          Write a starter markdown file with example structure
md2any doctor              Probe optional CLIs, bundled fonts, build features
md2any licenses            Print the bundled-font licence notice

  -o, --output <PATH>      Output file, or directory for svg/png
                           (default: from -o extension, else input.pptx;
                           image sequences default to input-svg/input-png)
      --format <NAME>      pptx | odp | pdf | docx | odt | html | svg | png
      --theme <NAME>       light | dark
      --aspect <RATIO>     16:9 | 4:3 | 9:16 | a4[-landscape] | a3 | a5 |
                           letter[-landscape] | legal | tabloid |
                           WxH[unit] custom (px / mm / cm / in / pt / emu)
      --layout <NAME>      clean | studio | frame | bold
      --break-mode <MODE>  smart | simple | off
      --break-fill <PCT>   Fill target before breaking, 50-120 (default 100)
      --table-fit <MODE>   auto | split | transpose | off
      --code-theme <MODE>  dark | light | match (default: dark)
                           Code block palette, independent of --theme
      --code-columns <MODE>
                           single | auto | two-up (default: single)
                           Landscape two-up code flow; fences can set columns=2
      --math <MODE>        unicode | source | svg (default: unicode)
                           svg uses built-in display layout; no TeX runtime
      --math-scale <N>     Scale generated display math, 0.35-3.0
      --math-block-align <ALIGN>
                           left | center | right for generated display math
      --math-max-height <PX>
                           Max generated display math height
      --doc-style <STYLE>  plain | report | handout | speaker-notes
                           DOCX/ODT document profile (default: report)
      --title <STRING>     Override deck title
      --author <STRING>    Override deck author
      --font <NAME>        Override body / title font (PPTX/ODP/DOCX/ODT)
      --logo <PATH>        Logo image rendered in slide footer
      --remote-image-cache <PATH>
                           Directory used to cache http(s) image downloads
                           (default: platform cache directory)
      --no-remote-image-cache
                           Fetch http(s) images on every render
      --remote-image-user-agent <STRING>
                           User-Agent sent when fetching remote images
      --theme-file <PATH>  YAML colour/font/size overlay
      --handout <N>        PDF only: 2/4/6 slides per A4 portrait page
      --with-notes         PDF only: emit one notes page per slide
      --notes-page-size <SIZE>
                           slide | a4 (default: slide)
      --notes-layout <LAYOUT>
                           auto | below | side-by-side (default: auto)
      --speaker-package <DIR>
                           Deck + notes PDF + handout PDF + manifest
      --pdf-font <PATH>    PDF only: TTF/OTF sans/body font
      --pdf-mono-font <PATH>
                           PDF only: TTF/OTF mono/code font
      --font-fallback <PATH[,PATH...]>
                           PDF only: fallback fonts for missing glyphs
      --font-audit         Report PDF glyph coverage and exit
      --cjk <PATH>         PDF only: TTF/OTF font used as per-character
                           fallback when DejaVu can't render a glyph
                           (typically a Noto CJK or system CJK font)
      --watch              Watch the markdown input file(s) and rebuild on change
                           (external deps like images / theme-file / logo are
                           not tracked — restart if those change)
      --serve              Start localhost HTTP preview with hot reload
      --serve-format <FMT> pdf | html | svg | png (default: pdf)
      --port <N>           Port for --serve (default 8421)
      --check              Lint mode; exit code 2 if any warnings
      --outline            Print one-line-per-slide outline (page, kind, blocks,
                           title) and exit. No output file is written.
      --emit-ir <PATH>     Write post-pagination IR JSON
      --emit-plan <PATH>   Write estimated render-plan JSON
      --trace-layout       Print render-plan summary to stderr
  -q, --quiet              Suppress summary line
  -h, --help               Print this brief help
      --help-pptx          Generate the user manual as PPTX
      --help-odp           Generate the user manual as ODP
      --help-pdf           Generate the user manual as PDF
      --help-docx          Generate the user manual as Word DOCX
      --help-odt           Generate the user manual as LibreOffice ODT
      --help-html          Generate the user manual as standalone HTML
      --help-svg           Generate the user manual as one SVG per slide
      --help-png           Generate the user manual as one PNG per slide
      --help-md            Print the user-manual Markdown source to stdout
  -V, --version            Print version
```

## Combining flags

The `--help-*` flags respect every other flag.

```bash
md2any --help-pdf --theme dark --layout studio
md2any --help-pptx --aspect 9:16
md2any --help-odt --theme-file brand.yaml -o brand-manual.odt
md2any --help-md | head -100
```

Same is true for normal runs — every flag composes with every other.

# Speaker notes

## How to attach notes

Put an HTML comment starting with `notes:` or `speaker notes:` anywhere on the slide:

```markdown
## A slide title

Visible content here.

<!-- notes: Reminder to reference the Q3 numbers and pause for questions. -->
```

Multiple `<!-- notes: -->` comments on one slide are concatenated.

Notes attach in **PPTX** and **ODP** outputs (visible in Presenter View or printed as Notes Pages). For DOCX and ODT, use `--doc-style speaker-notes` to append the visible document with a speaker-notes appendix.

For PDF, pass `--with-notes` to produce a presenter-friendly companion document: one notes page per slide with the slide thumbnail and speaker notes. By default, notes pages use the deck's own page size and aspect ratio, so a 16:9 deck produces 16:9 notes pages with the thumbnail and notes side by side. For print-oriented A4 pages, add `--notes-page-size a4`. Use `--notes-layout below` or `--notes-layout side-by-side` when you want to force the thumbnail/notes arrangement instead of the automatic aspect-based choice.

```bash
md2any talk.md --with-notes -o talk-notes.pdf
md2any talk.md --with-notes --notes-page-size a4 -o talk-notes-a4.pdf
md2any talk.md --with-notes --notes-layout below -o talk-notes-below.pdf
```

Mutually exclusive with `--handout` — pick one PDF post-processor at a time.

# Transitions

## Animated section changes

Set a deck-wide transition in front matter:

```yaml
transition: fade
transition_duration: 0.6
```

Supported across PPTX, ODP, and PDF: `fade`, `push`, `wipe`, `cover`, `split`. DOCX and ODT ignore transitions (they're documents, not slides).

# Internationalisation

## Right-to-left

```yaml
direction: rtl
```

Flips paragraph alignment and adds `rtl="1"` markers throughout PPTX and
ODP output for Arabic, Hebrew, and other RTL scripts. PDF output now
embeds DejaVu Sans, which covers Arabic, Hebrew, and other complex
scripts at the glyph level; full bidirectional reordering and joining
behaviour still depends on the viewer's PDF text layout engine.

## PDF fonts and glyph audit

For **PPTX / ODP / DOCX / ODT**, pass `--font` (or set `font:` in front matter) to a CJK-capable typeface — `Noto Sans CJK SC`, `Microsoft YaHei`, `Hiragino Sans`, `Yu Gothic`, etc. The slide consumer renders with that font, so Chinese / Japanese / Korean characters pass through unchanged.

For **PDF**, md2any embeds and subsets bundled DejaVu Sans by default. Use `--pdf-font` and `--pdf-mono-font` to replace the sans/body and mono/code faces with user-supplied TTF/OTF files. Use `--font-fallback PATH[,PATH...]` for additional per-character fallback fonts when the primary face cannot render a glyph.

```bash
md2any talk.md -o talk.pdf \
    --pdf-font ./fonts/Inter-Regular.ttf \
    --pdf-mono-font ./fonts/JetBrainsMono-Regular.ttf
```

For Chinese/Japanese/Korean PDFs, `--cjk` remains the small-binary convenience alias for adding one large CJK fallback font:

```bash
md2any talk.md -o talk.pdf \
    --cjk /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc
```

Only the glyphs your deck actually uses are embedded (subsetting handles the rest), so a 20 MB Noto CJK source typically turns into a small KB-scale addition to the output PDF.

Use `--font-audit` before rendering to see which glyphs require fallback fonts and which glyphs are missing entirely:

```bash
md2any talk.md --font-audit
md2any talk.md --font-audit --font-fallback ./fonts/NotoSansMath-Regular.ttf
```

# Performance

## How fast is fast

Current `HELP.md`, rendered by the release binary on this machine:

| Workload | PPTX | ODP | DOCX | ODT | HTML | PDF |
|----------|------|-----|------|-----|------|-----|
| 192-slide embedded manual | 15 ms | 9 ms | 5 ms | 4 ms | 2 ms | 70 ms |
| Output size | 438 KB | 59 KB | 47 KB | 41 KB | 442 KB | 476 KB |

Image-sequence outputs write one file per slide:

| Workload | SVG | PNG |
|----------|-----|-----|
| 192-slide embedded manual | 4 ms / 192 files | 1086 ms / 192 files |
| Output size | 665 KB | 46 MB |

# Limitations

## What md2any is *not*

md2any is a focused artifact generator, not a general-purpose document toolchain. If your needs go beyond the list below, you probably want a different tool:

- **Not Pandoc.** No `--from`/`--to` arbitrary format conversion, no Lua filters, no templating engine, no bibliography/citation handling, no cross-reference tracking, no extension-rich Markdown dialects (CommonMark + GFM tables + the small md2any-specific directives are the whole grammar).
- **Not Quarto.** No literate execution, no R/Python/Julia code execution at build time, no notebook ingestion, no website / book project structure, no observable cells.
- **Not a TeX engine.** Math support includes the Unicode subset documented in the Math reference, built-in SVG display math via `--math svg`, and full-page native math layout for `text-full` `math` blocks. It still does not run TeX, number equations, or solve cross-references.
- **Not a layout DSL.** Per-slide layout has a couple of opt-in directives; if you need fine-grained per-element positioning, build the deck in PowerPoint or Keynote directly.

Pandoc is the general converter. Quarto is a publishing system. md2any is a one-binary artifact generator for the narrower case of "I have one Markdown file and I want all eight common deliverable formats out the other side."

## What's not supported

- GIF and WebP images (PNG, JPEG, and SVG are supported)
- Embedded HTML beyond the notes / bg / column-break / layout directives
- Inline presenter-note pages inside DOCX / ODT. Use `--doc-style speaker-notes` for a notes appendix; PPTX / ODP attach notes natively and PDF gets notes pages via `--with-notes`.
- Complex text shaping in PDF — custom PDF fonts and fallback glyphs are supported, but full script shaping/reordering still depends on viewer behaviour
- Citations / bibliographies / cross-references — no `[@cite]` parsing, no `\ref{}`, no auto-generated reference list
- Diagram rendering requires the corresponding CLI on `$PATH` (`dot` / `mmdc` / `plantuml`). When absent, the fence stays as a regular code block — md2any never bundles diagram engines
- DOCX / ODT are flowing documents, not slide carriers. Section breaks come from H1; everything else flows. Pagination is the consumer app's job

## Honest tradeoffs in PDF

PDF output uses DejaVu Sans + DejaVu Sans Mono by default, embedded inside the md2any binary (~3 MB of the binary footprint). This buys Unicode coverage across Greek, Cyrillic, math operators, sub/superscripts, and most of European Latin without depending on the viewer's installed fonts. Other font families are loaded only when you provide TTF/OTF paths with `--pdf-font`, `--pdf-mono-font`, `--font-fallback`, or `--cjk`; they are subset so only used glyphs enter the PDF.

Font subsetting is automatic — each PDF embeds only the glyphs that deck actually uses, not the full 3 MB face. This manual (135 slides, heavy on tables and math) lands under 400 KB; a typical talk-sized deck is well under 200 KB even with code, tables, and the full Greek / math toolbox.

Inline code in PDF is rendered with DejaVu Sans Mono — slightly different from Consolas in PPTX/ODP. Visually noticeable to designers, irrelevant to readers.

Editability is gone in PDF. That's the entire point of the PDF format.

## Bundled font licence

The DejaVu / Bitstream Vera / Arev font licence requires that the notice travels with the font programs. Because the font bytes are embedded in the binary, md2any ships the full notice inside the executable too — print it any time with:

```bash
md2any licenses
```

Distributors building release archives that include only the standalone binary should include `assets/fonts/LICENSE.md` (or the output of `md2any licenses`) alongside it in the archive or release notes.

## Viewer compatibility

| Format  | Tool / viewer                  | Status                                                              |
|---------|--------------------------------|---------------------------------------------------------------------|
| PPTX    | Microsoft PowerPoint (Win/Mac) | **Verified.** Renders with Calibri / Calibri Light installed.       |
| PPTX    | Keynote (macOS)                | **Expected.** Opens via standard OOXML import; font substitution applies if Calibri absent. |
| PPTX    | LibreOffice Impress            | **Verified.** Calibri substituted to Carlito; layout near-identical. |
| PPTX    | Google Slides (web)            | **Expected.** Upload via Drive; theme survives, font substitution applies. |
| ODP     | LibreOffice Impress            | **Verified.** Reference renderer; opens natively.                    |
| ODP     | Keynote                        | **Partial.** Opens but loses some theme details on import.           |
| ODP     | Microsoft PowerPoint           | **Partial.** Imports via ODF support; image fidelity OK, theme drifts. |
| PDF     | Any standards-compliant viewer | **Verified.** Self-contained — DejaVu Sans + CJK fallback embedded.  |
| DOCX    | Microsoft Word                 | **Verified.** Standard OOXML; opens cleanly.                         |
| DOCX    | LibreOffice Writer             | **Verified.** Via headless render. Mixed bullet/number lists kept.   |
| DOCX    | Google Docs                    | **Expected.** Upload via Drive; styles preserved.                    |
| ODT     | LibreOffice Writer             | **Verified.** Reference renderer.                                    |
| ODT     | Microsoft Word                 | **Partial.** Word's ODF import is decent for body text; some style names mapped lossily. |

"Verified" = exercised by the renderer test suite and/or manually opened. "Expected" = standards-compliant format, should work but not part of routine testing. "Partial" = opens, but with known fidelity caveats listed alongside.

# Tips

## Pick a layout, commit

A 30-slide deck that mixes layouts mid-flow feels chaotic. Pick `clean`, `studio`, `frame`, or `bold` at the top of the file and don't change it.

If you want to A/B compare, run it twice with `--layout`. Same Markdown, different output names.

## Keep titles tight

The title bar has a fixed height. A 20-word H2 will overflow or scale uncomfortably. Aim for 3 to 7 words. Sub-headings on the same slide can carry the longer phrasing.

## Use `:::` columns sparingly

Columns work well for comparisons and quick cross-references. Don't put every slide in columns — the visual rhythm flattens.

## Author once, deliver everywhere

Use `--watch` + `--serve` during authoring, then on release:

```bash
md2any talk.md -o talk.pptx                # speaker copy
md2any talk.md -o talk.pdf                 # archive
md2any talk.md -o talk.docx                # written companion
md2any talk.md --handout 4 -o talk-handout.pdf  # printed handout
md2any talk.md --speaker-package release/  # deck + notes + handout + manifest
```

Same source, every artefact. Update the markdown; everything regenerates in milliseconds.

# Showcase

## What md2any can do, on one screen

The remaining slides exercise every feature on real content. If the format you're reading this in renders every page below cleanly, your toolchain is set up correctly.

## Math — Greek and Hebrew

$\alpha, \beta, \gamma, \delta, \epsilon, \zeta, \eta, \theta, \iota, \kappa, \lambda, \mu, \nu, \xi, \pi, \rho, \sigma, \tau, \upsilon, \phi, \chi, \psi, \omega$

$\Gamma, \Delta, \Theta, \Lambda, \Xi, \Pi, \Sigma, \Phi, \Psi, \Omega$

$\aleph_0, \aleph_1, \aleph_2 \ldots$

## Math — operators and relations

$\sum_{i=1}^{n} i = \frac{n(n+1)}{2}$

$\prod_{k=1}^{n} k = n!$

$\int_{a}^{b} f(x)\, dx = F(b) - F(a)$

$\nabla \cdot E = \rho / \epsilon_0$ (Gauss's law)

$a \leq b \neq c \geq d \approx e \equiv f \propto g$

$\forall \epsilon > 0,\ \exists \delta > 0 : |x - x_0| < \delta \Rightarrow |f(x) - f(x_0)| < \epsilon$

## Math — fractions, roots, binomials

Pythagorean: $c = \sqrt{a^2 + b^2}$

Quadratic: $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$

Choose: $\binom{n}{k} = \frac{n!}{k!\,(n-k)!}$

Golden ratio: $\phi = \frac{1 + \sqrt{5}}{2}$

Geometric series: $\sum_{n=0}^{\infty} r^n = \frac{1}{1 - r}, \quad |r| < 1$

## Math — famous equations

Euler's identity: $$e^{i\pi} + 1 = 0$$

Cauchy–Schwarz: $$\left( \sum_{i=1}^{n} a_i b_i \right)^2 \leq \left( \sum_{i=1}^{n} a_i^2 \right) \left( \sum_{i=1}^{n} b_i^2 \right)$$

Heisenberg uncertainty: $$\sigma_x \sigma_p \geq \frac{\hbar}{2}$$

## Code — Rust

```rust
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct Counter<K: Eq + std::hash::Hash> {
    items: HashMap<K, usize>,
}

impl<K: Eq + std::hash::Hash> Counter<K> {
    pub fn new() -> Self {
        Self { items: HashMap::new() }
    }

    pub fn bump(&mut self, k: K) -> usize {
        let n = self.items.entry(k).or_insert(0);
        *n += 1;
        *n
    }
}

fn main() {
    let mut c = Counter::new();
    for word in "the quick brown fox jumps over the lazy dog".split_whitespace() {
        c.bump(word);
    }
    println!("{:?}", c);
}
```

## Code — Python

```python
from dataclasses import dataclass
from typing import Iterable

@dataclass
class Page:
    title: str
    words: int

def summary(pages: Iterable[Page]) -> dict[str, int]:
    """Aggregate page stats by title prefix."""
    out: dict[str, int] = {}
    for p in pages:
        bucket = p.title.split()[0]
        out[bucket] = out.get(bucket, 0) + p.words
    return out

if __name__ == "__main__":
    pages = [Page("Intro to Rust", 1200), Page("Intro to Go", 980)]
    print(summary(pages))
```

## Code — JavaScript + TypeScript

```javascript
export function chooseAnswer(question) {
  const normalized = question.trim().toLowerCase();
  if (normalized.includes("life")) return 42;
  return Math.floor(Math.random() * 10);
}

console.log(chooseAnswer("life, universe, everything"));
```

```typescript
type Result<T, E> = { ok: true; value: T } | { ok: false; err: E };

async function fetchJson<T>(url: string): Promise<Result<T, string>> {
  const res = await fetch(url);
  if (!res.ok) return { ok: false, err: `HTTP ${res.status}` };
  try {
    const value = (await res.json()) as T;
    return { ok: true, value };
  } catch (e) {
    return { ok: false, err: String(e) };
  }
}

const r = await fetchJson<{ name: string }>("/api/me");
console.log(r.ok ? `hello ${r.value.name}` : `oops: ${r.err}`);
```

## Code — Go

```go
package main

import (
    "fmt"
    "sync"
)

func parallelMap[T, U any](items []T, fn func(T) U) []U {
    out := make([]U, len(items))
    var wg sync.WaitGroup
    for i, item := range items {
        wg.Add(1)
        go func(i int, item T) {
            defer wg.Done()
            out[i] = fn(item)
        }(i, item)
    }
    wg.Wait()
    return out
}

func main() {
    squared := parallelMap([]int{1, 2, 3, 4}, func(n int) int { return n * n })
    fmt.Println(squared)
}
```

## Code — C and C++

```c
#include <stdio.h>

int clamp(int value, int min, int max) {
    if (value < min) return min;
    if (value > max) return max;
    return value;
}

int main(void) {
    printf("%d\n", clamp(42, 0, 10));
}
```

```cpp
#include <algorithm>
#include <ranges>
#include <vector>

std::vector<int> evens(std::vector<int> xs) {
    auto view = xs | std::views::filter([](int n) { return n % 2 == 0; });
    return {view.begin(), view.end()};
}
```

## Code — JVM and .NET

```java
record User(String name, int score) {}

class Leaderboard {
    static boolean qualifies(User user) {
        return user.score() >= 42;
    }
}
```

```kotlin
data class Slide(val title: String, val lines: Int)

fun Slide.isDense(): Boolean =
    lines > 12 && title.isNotBlank()
```

```scala
case class Build(name: String, passed: Boolean)

val summary = builds.groupBy(_.passed).view.mapValues(_.size)
```

```csharp
public record Slide(string Title, int Lines);

public static bool Fits(Slide slide) =>
    slide.Lines <= 12 && !string.IsNullOrWhiteSpace(slide.Title);
```

## Code — SQL

```sql
WITH monthly_revenue AS (
  SELECT
    DATE_TRUNC('month', order_date) AS month,
    SUM(amount) AS revenue,
    COUNT(DISTINCT customer_id) AS customers
  FROM orders
  WHERE order_date >= NOW() - INTERVAL '12 months'
  GROUP BY 1
)
SELECT
  month,
  revenue,
  customers,
  revenue::numeric / NULLIF(customers, 0) AS arpu,
  LAG(revenue) OVER (ORDER BY month) AS prev_month,
  revenue - LAG(revenue) OVER (ORDER BY month) AS delta
FROM monthly_revenue
ORDER BY month DESC;
```

## Code — shell

```bash
#!/usr/bin/env bash
set -euo pipefail

deploy() {
  local env="$1" tag="$2"
  echo "→ deploying $tag to $env"
  kubectl --context "$env" set image deployment/api api="ghcr.io/acme/api:$tag"
  kubectl --context "$env" rollout status deployment/api --timeout=120s
}

for env in staging prod; do
  deploy "$env" "${TAG:-latest}"
done
```

```ruby
Slide = Data.define(:title, :lines)

deck = [
  Slide.new("Intro", 5),
  Slide.new("Implementation", 18)
]

puts deck.select { |slide| slide.lines > 12 }.map(&:title)
```

```powershell
function Publish-Deck {
    param([string] $Path, [string] $Target = "staging")
    Write-Host "Publishing $Path to $Target"
    Copy-Item $Path "\\fileserver\decks\$Target"
}

Publish-Deck -Path ".\talk.pdf" -Target "prod"
```

## Code — JSON + YAML + TOML

```json
{
  "name": "md2any",
  "version": "0.1.0",
  "outputs": ["pptx", "odp", "pdf", "docx", "odt"],
  "compact": true,
  "deps": null
}
```

```yaml
name: md2any
version: 0.1.0
outputs:
  - pptx
  - odp
  - pdf
  - docx
  - odt
features:
  remote_images: true
  svg: true
```

```toml
[package]
name = "md2any"
version = "0.1.0"
edition = "2021"

[dependencies]
clap = { version = "4.5", features = ["derive"] }
pulldown-cmark = "0.10"
```

## Code — config and docs

```dockerfile
FROM rust:1.74 AS build
WORKDIR /src
COPY . .
RUN cargo build --release

FROM debian:stable-slim
COPY --from=build /src/target/release/md2any /usr/local/bin/md2any
ENTRYPOINT ["md2any"]
```

```properties
spring.application.name=deck-service
feature.remote-images=true
render.timeout.seconds=30
```

```ini
[server]
host = 127.0.0.1
port = 8080
```

```env
MD2ANY_THEME=light
MD2ANY_FORMAT=pdf
```

```markdown
## Release checklist

- Build the binary
- Render `--help-pdf`
- Check the output before tagging
```

## Code — Haskell, BCPL, and BF

```haskell
loop :: IO ()
loop = do
  print (0 == 0)
  loop
```

```bcpl
GET "LIBHDR"

LET start() BE
$(
  FOR i = 1 TO 3 DO writes("BCPL still has opinions!*N")
  RESULTIS 0
$)
```

```bf
++++++[>+++++++<-]>.
```

## Code — web components

```html
<article class="slide-card">
  <h2>One source, many outputs</h2>
  <p>Markdown in, deck out.</p>
</article>
```

```css
.slide-card {
  display: grid;
  gap: 0.75rem;
  border: 1px solid var(--divider);
}
```

```xml
<deck title="Release notes">
  <slide id="intro">Ship it</slide>
</deck>
```

```vue
<template>
  <button @click="count++">count: {{ count }}</button>
</template>

<script setup lang="ts">
import { ref } from "vue";
const count = ref(0);
</script>
```

```svelte
<script lang="ts">
  let answer = 42;
</script>

<button on:click={() => answer += 1}>
  answer = {answer}
</button>
```

```astro
---
const title = "Static by default";
---
<h1>{title}</h1>
<p>Hydrate only what needs it.</p>
```

## Code — API and config

```graphql
query Talk($id: ID!) {
  talk(id: $id) {
    title
    speaker { name }
  }
}
```

```http
POST /api/talks HTTP/1.1
Host: example.test
Content-Type: application/json

{"title":"Markdown everywhere","slides":42}
```

```terraform
resource "aws_s3_bucket" "slides" {
  bucket = "md2any-release-artifacts"
}
```

```hcl
variable "region" {
  type    = string
  default = "eu-central-1"
}
```

```diff
@@ syntax coverage @@
- twenty languages
+ forty-plus tags across modern and vintage stacks
```

## Code — mainframe

md2any ships syntax tables for COBOL, JCL, REXX, PL/1 (also tagged `pli` or `plx`), HLASM, DB2, fixed-form RPG/RPG II/RPG III, free-form RPGLE, and IBM i CL alongside the modern languages. Handy when documentation has to live in the same deck as a mainframe migration story.

```cobol
       IDENTIFICATION DIVISION.
       PROGRAM-ID. HELLO.
       PROCEDURE DIVISION.
           DISPLAY 'HELLO, MAINFRAME'.
           STOP RUN.
```

```jcl
//PAYROLL  JOB  (ACCT),'NIGHTLY RUN',CLASS=A,MSGCLASS=H
//STEP1    EXEC PGM=IDCAMS
//SYSPRINT DD   SYSOUT=*
//SYSIN    DD   *
  LISTCAT ENTRIES('PROD.PAYROLL.MASTER')
/*
```

```rexx
say 'REXX can still glue the night shift together'
parse arg dataset
if dataset = '' then dataset = 'PROD.PAYROLL.MASTER'
say 'checking' dataset
```

```pl1
HELLO: PROC OPTIONS(MAIN);
  PUT SKIP LIST('PL/I says hello, and probably means it.');
END HELLO;
```

```rpg2
     FSALES   IF   E           K DISK
     C           *ENTRY    PLIST
     C                     PARM           CUSTNO            6 0
     C           CUSTNO    CHAINSALESR              99
     C           *IN99     IFEQ *OFF
     C                     EXCPTDETAIL
     C                     ENDIF
```

```rpgle
**free
ctl-opt dftactgrp(*no) option(*srcstmt:*nodebugio);

dcl-s customer char(10) inz('S/38');
if %trim(customer) <> '';
  dsply ('Order for ' + customer);
endif;
```

```cl
PGM PARM(&LIB &FILE)
  DCL VAR(&LIB) TYPE(*CHAR) LEN(10)
  DCL VAR(&FILE) TYPE(*CHAR) LEN(10)
  MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(ERROR))
  IF COND(&LIB *EQ '*LIBL') THEN(DO)
    SNDPGMMSG MSG('Library list still wins')
  ENDDO
  CALL PGM(&LIB/LOADORDERS) PARM(&FILE)
  RETURN
ERROR:
  SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGTYPE(*ESCAPE)
ENDPGM
```

```hlasm
HELLO    CSECT
         WTO   'HELLO FROM HLASM'
         BR    14
         END   HELLO
```

```db2
CREATE TABLE audit_event (
  id BIGINT GENERATED ALWAYS AS IDENTITY,
  event_time TIMESTAMP NOT NULL,
  payload CLOB
);

SELECT id, event_time
FROM audit_event
WHERE event_time >= CURRENT TIMESTAMP - 1 DAY;
```

## Tables

| Format | Editable | Slides | Docs | Notes |
|--------|:--------:|:------:|:----:|-------|
| PPTX   | yes      | ✓      |      | speaker notes, transitions |
| ODP    | yes      | ✓      |      | open source replacement |
| PDF    | no       | ✓      | ✓    | font-embedded, copy-pasteable |
| DOCX   | yes      |        | ✓    | document flow |
| ODT    | yes      |        | ✓    | open source replacement |

## Side-by-side columns

`:::` splits a slide into two columns. Useful for compare-and-contrast.

## Pros and cons

Markdown source on the left, polished output on the right. Author once, deliver to eight formats, no Office on the build machine, no JRE, no Python pipeline. Fast cold start, fast warm rebuild.

:::

The trade-off: visuals are constrained to what md2any knows about. No SmartArt, no animations beyond simple transitions, no embedded video. If you need those, this isn't the right tool.

## CJK — Chinese, Japanese, Korean

Generate with `--cjk /path/to/NotoSansCJK.ttc` to embed CJK glyphs in PDF (PPTX/ODP/DOCX/ODT just need `--font` set to a CJK family).

- 中文:你好世界,欢迎使用 md2any。
- 日本語:こんにちは、世界。md2any へようこそ。
- 한국어:안녕하세요 세계. md2any에 오신 것을 환영합니다.

Mixed runs work inline too — *md2any* handles **中文** and `日本語` and `한국어` in the same paragraph without breaking line layout.

## Unicode coverage

DejaVu Sans ships ~5,800 glyphs, covering Latin, Greek, Cyrillic, Hebrew, Arabic, math, and arrows. A whirlwind tour:

- Currency: € £ ¥ ₹ ₽ ₩ ฿ ₪ ₺ ₴
- Arrows: ← → ↑ ↓ ↔ ⇐ ⇒ ⇔ ⇆ ↻ ↺
- Math: ∀ ∃ ∄ ∅ ∈ ∉ ∋ ∏ ∑ ∫ ∮ ∝ ∞ ∇ ∂ √ ∛ ∜ ≈ ≠ ≡ ≤ ≥ ⊂ ⊃ ⊆ ⊇ ∪ ∩
- Logic: ¬ ∧ ∨ ⊕ ⊻ ⊤ ⊥ ⊢ ⊨
- Set theory: ℕ ℤ ℚ ℝ ℂ ℙ ℵ ℶ
- Geometry: △ ▽ ◇ ◯ ▲ ▼ ◆ ● ★ ☆
- Drawing: ─ │ ┌ ┐ └ ┘ ├ ┤ ┬ ┴ ┼ ━ ┃ ┏ ┓ ┗ ┛
- Music: ♩ ♪ ♫ ♬ ♭ ♮ ♯
- Misc: ™ © ® § ¶ † ‡ ‰ ‽ ⁂ ※

## Footnotes

Markdown footnotes are gathered per slide, not per deck — references stay near their definitions[^near].

You can drop *multiple* references on one slide[^multi] and md2any will collect their definitions at the bottom in source order[^order].

[^near]: Useful when slides are rearranged: the footnote moves with the slide that owns it.

[^multi]: Numbered automatically; you write `[^id]` and md2any picks the superscript.

[^order]: Same applies to PDF, DOCX, and ODT outputs — the footnote block follows the same per-slide grouping.

## Blockquotes

> The best documentation is the kind you can hand to your future self at 2 a.m. and still understand.

> "Plain text in, polished slides out" is the whole pitch. — *md2any README*

## Diagrams

````
```dot
digraph pipeline {
  rankdir=LR;
  node [shape=box, style=rounded];
  Markdown -> Parser -> Paginator -> Renderer -> "{pptx, odp, pdf, docx, odt, html, svg, png}";
}
```
````

If `dot` is on your `$PATH`, this fence rasterises into a PNG embedded in the slide. Otherwise the fence stays as a regular code block. Same goes for `mermaid` and `plantuml`.

## Speaker notes

The slide says one thing; the speaker says another. Attach private notes that surface in Presenter View (PPTX / ODP), the `--with-notes` PDF, but never on the visible slide.

```markdown
## A slide title

The audience sees this.

<!-- notes: Remember to mention the Q3 numbers and pause for the
     question about pricing. The CFO will ask. -->
```

## Putting it all together

Markdown, math, code, tables, CJK, diagrams, footnotes, speaker notes — all from the same `.md` file, all in one binary, all rendered in milliseconds. The point isn't any one feature; it's that you only have to write the thing once.

# That's all

## Now go make something

Write Markdown. Run one command. Open the file. Present, send, print — whichever you need.

```bash
md2any my-talk.md
```

If you want to see this manual again in any format, just run:

```bash
md2any --help-pptx       # or --help-odp, --help-pdf, --help-docx, --help-odt, --help-html, --help-svg, --help-png, --help-md
```