Hebrew slide-Markdown → PPTX
Converts a Markdown deck written in the slide-authoring format into a clean,
RTL-aware .pptx skeleton. This is the slide counterpart of the
hebrew-md-to-docx skill, and the inverse of pptx-to-slide-md (so a deck can
round-trip: PPTX → slide-Markdown → PPTX).
Why this skill exists
Pasting slide-Markdown into PowerPoint forces the user to right-align every
Hebrew paragraph by hand, and still leaves bugs: punctuation and brackets around
English (ו-CTO., [^]) drift to the wrong side, and every Hebrew word is
underlined as a spelling mistake because the runs carry no Hebrew language tag.
This skill fixes all of that at the OOXML level and lays out one slide per block
with the title, body, and speaker notes in the right places.
How to use
The converter is md_to_pptx_he.py (Python 3; needs python-pptx, mistune,
and Pillow):
pip install python-pptx mistune Pillow --break-system-packages # if needed
python md_to_pptx_he.py INPUT.md -o OUTPUT.pptx
Options:
--template DECK.pptx – build on a template so the output inherits a specific
theme, fonts, and slide layouts (see below). Without it, python-pptx's plain
default theme is used.
--overrides overrides.json – pin the base direction of ambiguous paragraphs
({ "3": "rtl", "12": "ltr" }, keyed by the index printed to stderr).
--code-font Consolas – monospace font for code spans/blocks. Default
Consolas.
Slide size: without a template the deck is 16:9 widescreen (13.33"×7.5"), and
the title/body placeholders are widened to fill it. With --template, the
template's own slide size and layouts are kept as-is.
By default, run the converter without --template — it uses python-pptx's
plain default theme, since the output is meant to be styled afterwards anyway.
Only use --template DECK.pptx if the user explicitly asks for a specific
template, theme, fonts, or layouts to be applied.
Input format
The document is a sequence of slide blocks. --- on its own line separates
slides; === separates a slide's body from its speaker notes.
# [Section 1: Section Name (~time)] <- starts a native PowerPoint section
## [Slide 1: Brief Description] <- scaffolding label, dropped from the slide
# Slide Title <- the real slide title
Body markdown: bullets, numbered lists, tables, **bold**, *italic*, `code`, [links](url).
[presenter instruction] <- moved to the speaker notes
[image: path/to/pic.png — "alt"] <- embedded onto the slide
[^] <- a click marker; also moved to notes
===
**Speaker Notes:**
Notes in markdown. Single line breaks are preserved.
---
## [Slide 2: ...]
# Next Slide Title
...
Key rules:
- Section labels
# [Section N: Name] start a native PowerPoint section. The
label Section N: is stripped; only the name (everything after the colon,
e.g. Section Name (~time)) is used. Every following slide belongs to that
section until the next section label.
- Slide labels
## [Slide N: ...] are scaffolding for the author and are
dropped. A lone [Slide N] line (as produced by pptx-to-slide-md) is also
recognised as a slide label and dropped, so an extracted deck round-trips.
- Slide title is the first
# Heading inside the body. # (untitled) (and
# (Slide N — untitled)) is treated as an empty title.
- Presenter instructions in
[brackets] inside the body — animations, demos,
[^] click markers, etc. — are removed from the slide and appended to the
speaker notes under a "Presenter instructions:" heading. ([text](url) is a
link, not an instruction, and is kept.)
- Images written as
[image: path — "alt"] are embedded onto the slide
(path resolved relative to the input .md). The alt text is ignored.
[hidden slide] markers are dropped (the converter does not re-hide slides).
Direction handling (the RTL core)
Unlike Word, PowerPoint sets text direction per paragraph, and there is no
per-run RTL flag. So:
- Each paragraph's base direction is chosen by the majority of strong
directional characters (Hebrew vs Latin), and written as
a:pPr/@rtl plus a
matching @algn (right for RTL, left for LTR).
- Within a paragraph, text is split into runs by script, and each run is tagged
with a language (
a:rPr/@lang = he-IL or en-US). This does two jobs:
the spell-checker uses the Hebrew dictionary for Hebrew runs (no more
everything-is-a-typo), and PowerPoint resolves bidi per run so neutral
punctuation (dash, dot, brackets) around English joins the Hebrew side instead
of drifting LTR. Digits stay LTR so numbers like 1920 never reverse.
- Near-even paragraphs are printed to stderr as ambiguous; resolve them with
--overrides keyed by the printed index.
- Tables whose header is Hebrew-dominant get right-to-left column order
(
a:tbl @rtl).
What gets converted
| Markdown |
PowerPoint |
# Title (first heading in body) |
slide title placeholder |
paragraphs, ##+ headings |
body placeholder paragraphs (headings bold) |
- / 1. lists |
bulleted / auto-numbered paragraphs with hanging indent |
**bold**, *italic*, ~~strike~~ |
run formatting |
`code` / ``` blocks |
monospace runs (LTR) |
[text](url) |
hyperlinked runs |
| tables |
a table shape (RTL column order when Hebrew) |
[image: ...] |
embedded picture |
body [brackets], [^] |
appended to speaker notes |
| speaker notes |
notes pane; single line breaks preserved |
Speaker notes
Notes keep the author's line structure: a single newline becomes a real line
break (Markdown would otherwise collapse it to a space). Bulleted/numbered notes
get a hanging indent so the marker is spaced from the text even though the notes
text frame defines no list styles.
Limitations
- The output is a plain, unstyled skeleton (default theme). Styling — colors,
fonts, layouts — is a deliberate later step.
- Table and image positioning is a rough estimate (text height can't be known in
advance), so a slide that mixes a lot of body text with a table/image may need
manual repositioning.
- Animations are not created; their description is only recorded in the notes.
- Hidden slides come through visible (the marker is dropped).
- Every content slide uses the "Title and Content" layout; pick other layouts by
hand afterwards.
1---2name: hebrew-md-to-pptx3description: Convert a Markdown file written in the user's slide-authoring format (with Hebrew or mixed Hebrew/English) into a basic, RTL-aware PowerPoint .pptx skeleton. Use whenever the user wants to turn slide-Markdown (blocks separated by `---`, content/notes separated by `===`, section/slide labels and presenter instructions in [brackets]) into an editable deck, or complains that pasting such Markdown into PowerPoint breaks right-to-left alignment, flips the punctuation around English, or flags every Hebrew word as a typo. Produces real title/body placeholders, native PowerPoint sections, speaker notes, tables, embedded images, and per-paragraph text direction. The output is intentionally unstyled, ready to be themed afterwards by hand or with the pptx skill.4---56# Hebrew slide-Markdown → PPTX78Converts a Markdown deck written in the slide-authoring format into a clean,9RTL-aware `.pptx` skeleton. This is the slide counterpart of the10`hebrew-md-to-docx` skill, and the inverse of `pptx-to-slide-md` (so a deck can11round-trip: PPTX → slide-Markdown → PPTX).1213## Why this skill exists1415Pasting slide-Markdown into PowerPoint forces the user to right-align every16Hebrew paragraph by hand, and still leaves bugs: punctuation and brackets around17English (`ו-CTO.`, `[^]`) drift to the wrong side, and every Hebrew word is18underlined as a spelling mistake because the runs carry no Hebrew language tag.19This skill fixes all of that at the OOXML level and lays out one slide per block20with the title, body, and speaker notes in the right places.2122## How to use2324The converter is `md_to_pptx_he.py` (Python 3; needs `python-pptx`, `mistune`,25and `Pillow`):2627```bash28pip install python-pptx mistune Pillow --break-system-packages # if needed29python md_to_pptx_he.py INPUT.md -o OUTPUT.pptx30```3132Options:3334- `--template DECK.pptx` – build on a template so the output inherits a specific35 theme, fonts, and slide layouts (see below). Without it, python-pptx's plain36 default theme is used.37- `--overrides overrides.json` – pin the base direction of ambiguous paragraphs38 (`{ "3": "rtl", "12": "ltr" }`, keyed by the index printed to stderr).39- `--code-font Consolas` – monospace font for code spans/blocks. Default40 `Consolas`.4142Slide size: without a template the deck is **16:9 widescreen** (13.33"×7.5"), and43the title/body placeholders are widened to fill it. With `--template`, the44template's own slide size and layouts are kept as-is.4546By default, run the converter without `--template` — it uses python-pptx's47plain default theme, since the output is meant to be styled afterwards anyway.48Only use `--template DECK.pptx` if the user explicitly asks for a specific49template, theme, fonts, or layouts to be applied.5051## Input format5253The document is a sequence of slide blocks. `---` on its own line separates54slides; `===` separates a slide's body from its speaker notes.5556```markdown57# [Section 1: Section Name (~time)] <- starts a native PowerPoint section58## [Slide 1: Brief Description] <- scaffolding label, dropped from the slide5960# Slide Title <- the real slide title61Body markdown: bullets, numbered lists, tables, **bold**, *italic*, `code`, [links](url).62[presenter instruction] <- moved to the speaker notes63[image: path/to/pic.png — "alt"] <- embedded onto the slide64[^] <- a click marker; also moved to notes6566===6768**Speaker Notes:**69Notes in markdown. Single line breaks are preserved.7071---7273## [Slide 2: ...]74# Next Slide Title75...76```7778Key rules:7980- **Section labels** `# [Section N: Name]` start a native PowerPoint section. The81 label `Section N:` is stripped; only the name (everything after the colon,82 e.g. `Section Name (~time)`) is used. Every following slide belongs to that83 section until the next section label.84- **Slide labels** `## [Slide N: ...]` are scaffolding for the author and are85 dropped. A lone `[Slide N]` line (as produced by `pptx-to-slide-md`) is also86 recognised as a slide label and dropped, so an extracted deck round-trips.87- **Slide title** is the first `# Heading` inside the body. `# (untitled)` (and88 `# (Slide N — untitled)`) is treated as an empty title.89- **Presenter instructions** in `[brackets]` inside the body — animations, demos,90 `[^]` click markers, etc. — are removed from the slide and appended to the91 speaker notes under a "Presenter instructions:" heading. (`[text](url)` is a92 link, not an instruction, and is kept.)93- **Images** written as `[image: path — "alt"]` are embedded onto the slide94 (path resolved relative to the input .md). The alt text is ignored.95- `[hidden slide]` markers are dropped (the converter does not re-hide slides).9697## Direction handling (the RTL core)9899Unlike Word, PowerPoint sets text direction per **paragraph**, and there is no100per-run RTL flag. So:101102- Each paragraph's base direction is chosen by the **majority of strong103 directional characters** (Hebrew vs Latin), and written as `a:pPr/@rtl` plus a104 matching `@algn` (right for RTL, left for LTR).105- Within a paragraph, text is split into runs by script, and each run is tagged106 with a **language** (`a:rPr/@lang` = `he-IL` or `en-US`). This does two jobs:107 the spell-checker uses the Hebrew dictionary for Hebrew runs (no more108 everything-is-a-typo), and PowerPoint resolves bidi per run so neutral109 punctuation (dash, dot, brackets) around English joins the Hebrew side instead110 of drifting LTR. Digits stay LTR so numbers like `1920` never reverse.111- Near-even paragraphs are printed to stderr as **ambiguous**; resolve them with112 `--overrides` keyed by the printed index.113- Tables whose header is Hebrew-dominant get right-to-left column order114 (`a:tbl` `@rtl`).115116## What gets converted117118| Markdown | PowerPoint |119| --- | --- |120| `# Title` (first heading in body) | slide title placeholder |121| paragraphs, `##`+ headings | body placeholder paragraphs (headings bold) |122| `-` / `1.` lists | bulleted / auto-numbered paragraphs with hanging indent |123| `**bold**`, `*italic*`, `~~strike~~` | run formatting |124| `` `code` `` / ```` ``` ```` blocks | monospace runs (LTR) |125| `[text](url)` | hyperlinked runs |126| tables | a table shape (RTL column order when Hebrew) |127| `[image: ...]` | embedded picture |128| body `[brackets]`, `[^]` | appended to speaker notes |129| speaker notes | notes pane; single line breaks preserved |130131## Speaker notes132133Notes keep the author's line structure: a single newline becomes a real line134break (Markdown would otherwise collapse it to a space). Bulleted/numbered notes135get a hanging indent so the marker is spaced from the text even though the notes136text frame defines no list styles.137138## Limitations139140- The output is a plain, unstyled skeleton (default theme). Styling — colors,141 fonts, layouts — is a deliberate later step.142- Table and image positioning is a rough estimate (text height can't be known in143 advance), so a slide that mixes a lot of body text with a table/image may need144 manual repositioning.145- Animations are not created; their description is only recorded in the notes.146- Hidden slides come through visible (the marker is dropped).147- Every content slide uses the "Title and Content" layout; pick other layouts by148 hand afterwards.