All notable changes to Prezo are documented in this file.
Starting with version 2026.1.1, Prezo uses CalVer versioning (YYYY.M.patch).
- Images in PDF/PNG/SVG/HTML export - Slide images (
![bg fit]/![bg]) are now embedded into exported PDF, PNG, SVG and HTML output (base64, so each file is self-contained). Previously image-only slides exported blank because the renderers ignored background images entirely.fitimages are letterboxed; others cover.
--no-emojiflag /[display] emojioption - Rewrites emoji to fixed-width ASCII markers (✅→[V],⚠️→/!\,❌→[X],❓→[?], …; decorative emoji are stripped). Terminals disagree with Rich on emoji cell width — some clip wide glyphs, others miscount VS16 sequences like⚠️and break box/table borders. Since no static width is correct for every terminal+font, this guarantees alignment by emitting only width-1 characters. The markers keep a colour cue ([V]green,/!\yellow,[X]red, …) via post-render recolouring, so they stand out in the TUI, HTML, and PNG/SVG/PDF export. Applies everywhere (keeping exports a faithful image of the console); arrows, box-drawing, and CJK text are left untouched.
- Stray
:::afterspacer/divider-::: spacerand::: dividerare void directives that take no body. A redundant closing:::(which the docs used to show, and which appears in many decks) is now consumed instead of leaking as literal text glued to the following line. - HTML export rendered raw Markdown -
--export htmlnow renders headings, lists, tables, code, and Pandoc-style fenced divs (::: columns,::: box,::: center,::: right,::: divider,::: spacer) into proper HTML elements. Previously the output dumped unrendered source (e.g.<p># Title</p>,<p>::: columns</p>) because themarkdownlibrary was never a runtime dependency and fenced divs were never routed through a renderer. - Presenter notes could not scroll - Long presenter notes were clipped with no way to reach the overflow. The notes panel is now a scroll container (mouse wheel + scrollbar), and
PageUp/PageDownscroll it from the keyboard while it's shown. - Help panel opened on launch (some terminals) - Pinned
textual-image < 0.13. Version 0.13.x issues terminal escape queries at startup whose responses can leak into stdin on some terminals, where the stray?triggered the help binding so prezo opened with the help screen.
markdownis now a runtime dependency - required for faithful HTML export (it was previously only referenced optionally and never installed).textual-imagepinned to< 0.13- 0.12.0 (the version shipped in the last release) is known good; see the help-panel fix above.
- Void directives - Tutorial now shows
::: spacer/::: dividerwithout a closing:::and notes the trailing marker is optional. - Box nesting - Documented that
::: boxbodies are plain Markdown: a layout div may contain a box, but a box cannot contain nested fenced divs.
- Inline formatting in boxes -
*italic*,`code`, and[links](url)inside::: boxblocks now render properly (previously only**bold**worked) - Wrapped bold/italic - Bold and italic spans in list items no longer lose their styling when word-wrapping splits them across lines
- Extra space before boxes - Removed the duplicated blank line that appeared before every box block (Rich's Markdown renderer already contributes the needed spacing)
- Cheat sheet - Documented link navigation mode (
Tab,j/k,Enter,Escape) and the-vversion flag
- Code blocks -
#comments inside fenced code blocks are no longer rendered as H1 headings - Bold in titles -
**bold**,*italic*,`code`and links in H1/H2 headings now render with proper styling instead of showing raw markers - URL splitting in lists - Markdown links and bare URLs in list items are no longer broken across lines during word wrapping
- Code quality improvements - Refactored complex functions
- Type annotations - Fixed type hints for compatibility with mypy, pyrefly & ty
- Textual API compatibility - Updated
stylesheet.add_source()call to use correct parameter names - Async action_quit - Fixed method signature to match Textual's async parent class
- Clickable links - Click on markdown links to open them (URLs open in browser, local files in default app)
- Link navigation mode - Press
Tabto enter link mode,j/kto navigate between links,Enterto open,Escapeto exit - Hanging indent for lists - Continuation lines of bullet points now align with text after the bullet, not with the bullet itself
- Self-closing spacers/dividers -
::: spacerand::: dividerno longer require a closing:::tag
- Inline images - Images without
bgdirective now display properly below the title (centered, taking available space) - Link path resolution - Relative paths in links resolve relative to the presentation file (consistent with image paths)
- Session resume - New
--resume/-rflag to restore session state (slide position, timer elapsed time, timer running state, theme) when relaunching a presentation - Image vertical fit - New
![bg right:fit]and![bg left:fit]syntax to size images to fill vertical space while maintaining aspect ratio - Custom themes - Define custom color themes in
~/.config/prezo/config.tomlusing[themes.name]sections - Custom CSS - Load custom Textual CSS from
~/.config/prezo/custom.tcss, config-specified path, or local./prezo.tcss
- Heading styles - H1 (heavy border panel) and H2 (centered bold) now render consistently across all slides
- Theme cycling - Backgrounds now update correctly when cycling through themes with
T - Bullet list spacing - One blank line before and after each bullet list block (was inconsistent)
- Numbered list spacing - Empty lines between list items in source no longer create extra spacing
- Updated cheat-sheet and tutorial with
--resumeandright:fit/left:fitsyntax
- Version flag - New
-v/--versionCLI option to display version - Timer start/stop - New
Skey to pause/resume the elapsed timer (shows ⏸ indicator when paused) - Pacing indicator - Color-coded indicator showing if you're ahead/behind schedule when a time budget is set (
--time-budgetflag ortime_budgetdirective)
- Box layout spacing - Stacked boxes now have exactly one blank line between them (was two)
- Box content spacing - Title followed by list no longer has extra blank line in boxes
--no-chromeexport - Fixed blank page output when exporting without window decorations- Export vertical spacing - Removed wasted blank lines at bottom of PDF/PNG/SVG exports
- Custom box content renderer for compact spacing (avoids Rich Markdown's paragraph gaps)
- Chrome PDF backend - Best quality PDF export using Chrome/Chromium headless
- PDF backend selection - New
--pdf-backendCLI option (auto, chrome, inkscape, cairosvg) - Demo presentation showcasing Prezo features (
docs/slides.md)
- PDF backend auto-detection now prefers Chrome > Inkscape > CairoSVG
- Export functions now return
Pathand raiseExportErrorinstead of returning(int, str)tuples - Export module refactored into a package (
export/) with separate modules for PDF, HTML, images, and SVG - Tutorial expanded into comprehensive user guide with CLI usage, keyboard shortcuts, configuration, and troubleshooting
- Column layouts - Pandoc-style fenced div syntax for multi-column slides
::: columns/::: columnfor side-by-side content- Support for 2, 3, or more columns
- Variable column widths (
::: column 30for 30% width) - Works in TUI, PDF export, and HTML export
- Centered content -
::: centerfor horizontally centered text - Right-aligned content -
::: rightfor right-aligned text (attributions, signatures) - Vertical spacing -
::: spacer [n]for adding blank lines (default 1) - Bordered panels -
::: box [title]for content in bordered boxes - Horizontal dividers -
::: divider [style]with styles: single, double, thick, dashed - Nested layout blocks - Layout blocks can be nested inside columns
- New
SlideContentwidget with layout support - New
layout.pymodule for parsing and rendering layouts - Demo presentations:
examples/columns_demo.md,examples/layout_demo.md
- Test suite reorganized into test pyramid structure (a_unit, b_integration, c_e2e)
- Emoji characters now render correctly in PDF export (added emoji font fallbacks)
- Switched from SemVer to CalVer versioning
- Pillow deprecation warnings (
getdata()replaced withget_flattened_data())
- Updated tutorial with missing features (image_mode directive, bg fit/contain, w:/h: size syntax)
- Added CHANGES.md changelog
- Type checker issues (mypy, pyrefly, ty)
- CI configuration
- Tweaked default CSS for better slide layout
- Noxfile for development automation
- Modal screens (help, overview, TOC, search) now use the current theme
Initial public release.
- Markdown presentations - MARP/Deckset format with
---slide separators - Live reload - Auto-refresh when file changes (1s polling)
- Keyboard navigation - Vim-style keys, arrow keys, and more
- Slide overview - Grid view for quick navigation (
o) - Search - Find slides by content (
/) - Table of contents - Navigate by headings (
t) - Go to slide - Jump to specific slide number (
:) - Presenter notes - Toggle notes panel (
p) - Themes - 6 color schemes (
Tto cycle): dark, light, dracula, solarized-dark, nord, gruvbox - Timer/Clock - Elapsed time and countdown (
c) - Edit slides - Open in $EDITOR (
e), saves back to source file - Export - PDF, HTML, PNG, SVG formats with customizable themes and sizes
- Image support - Inline and background images with MARP layout directives (left/right/fit)
- Native image viewing - Press
ifor full-quality image display (iTerm2/Kitty protocols) - Blackout/Whiteout - Blank screen modes (
b/w) - Command palette - Quick access to all commands (
Ctrl+P) - Config file - Customizable settings via
~/.config/prezo/config.toml - Recent files - Tracks recently opened presentations
- Position memory - Remembers last slide position per file