Skip to content

OpenStruct/crosspresent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crossPresent

Turn one Markdown file into a self-contained HTML presentation — charts, stat tiles, tables, cards and callouts included. No dependencies, no build chain, no JS in the output. Charts are rendered to inline SVG at build time, so the result is a single file that works offline, adapts to dark/light mode, and prints one slide per page.

It generalises a hand-rolled presentation design system into a reusable generator, so the next deck takes minutes, not hours.

Install

crossPresent is a single, dependency-free Python file. Install it as a crosspresent command:

pipx install .          # isolated CLI (recommended) — needs pipx
# or: uv tool install .
# or: pip install .      # into the current environment

Requires Python 3.8+ and nothing else. Prefer not to install? Every command below also works as python3 crosspresent.py … straight from the repo.

Quickstart

crosspresent new mydeck          # scaffold a starter deck
crosspresent build mydeck.md --open

That's it.

While writing, use live preview instead of rebuilding by hand:

crosspresent serve mydeck.md     # opens a browser; save = reload

Want to see everything it can do first? This builds a bundled showcase deck and opens it — no files needed, works from any directory:

crosspresent demo

(From a clone of the repo you can also build the source directly: crosspresent build examples/demo.md --open.)

Templates

Three built-in looks. Pick one in frontmatter (template: deck) or override at build time (-t deck):

Template What you get Best for
sidebar (default) Sticky table of contents + full-height scrolling sections Walkthroughs, screen-shared reviews
deck Full-screen slides with snap scrolling and a slide counter Actual presentations
doc Single column with a TOC box at the top Documentation, reports, READMEs-with-pictures

Same source file works with all three — examples/demo.html, examples/demo-deck.html and examples/demo-doc.html are the same Markdown built three ways.

Authoring guide

Frontmatter

---
title: My Deck                  # browser title (defaults to first slide)
subtitle: Shown under the cover heading.
eyebrow: Project walkthrough    # small label above the cover heading
template: sidebar               # sidebar | deck | doc
palette: default                # default | ocean | forest | mono | crimson
accent: "#ffb547"               # theme accent (optional, overrides palette)
background: "#0f1115"           # page background (optional, overrides palette)
toc_title: Contents             # sidebar heading (optional)
footer: My footer text          # page footer (optional)
---

Palettes

A palette sets the accent, the page background and the chart colors as a matched set, for both the dark and light schemes — pick one and everything agrees without touching a hex code (theme: works as an alias):

Palette Feel
default Amber accent on near-black — the original walkthrough look
ocean Cyan/blue, deep blue-black background
forest Greens and earth tones
mono Grayscale charts, neutral accent — print-friendly, serious
crimson Warm reds/pinks

Explicit keys win over the palette: set palette: ocean and accent: "#ff00aa" and you get ocean's backgrounds and chart colors with your accent.

Theming — accent and background

The output follows the system color scheme: a dark theme by default and a light theme when the viewer's OS prefers light. Both are themeable, and every key is optional — leave them out and you get the built-in look.

Key Default Applies to
accent #ffb547 dark scheme accent (eyebrows, notes, first chart color)
accent_light #c2530a light scheme accent (defaults to accent if you set one)
background #0f1115 dark scheme page background
background_light #fbfbfd light scheme page background
---
title: Branded deck
accent: "#7c5cff"
background: "#14101e"            # any CSS color — or a gradient:
# background: "linear-gradient(160deg, #14101e 0%, #1a1430 100%)"
---

Values are dropped into CSS as-is, so any valid CSS background value works (colors, gradients). Panels, cards and charts keep their own surfaces, so an override only needs to look right behind them — very dark values pair well with the dark accent palette, very light ones with the light palette.

Slides

  • # Title — a title slide (gradient background; first one is the cover)
  • ## Heading — a regular slide; auto-numbered, auto-added to the TOC
  • ## Heading {#custom-id} — set the anchor yourself
  • ### Heading — a sub-heading within the current slide
  • The first paragraph of each slide is styled as its intro line

Inline markup

**bold**  *italic*  `code`  [link](https://…)  ![alt](image.png)
[[BADGE]]            → neutral pill badge
[[shipped|good]]     → colored badge: good, warn, bad, info, accent, purple, teal, dim

Charts — fenced block tagged chart, JSON inside

```chart
{
  "type": "bar",
  "title": "Requests per day",
  "labels": ["Mon", "Tue", "Wed", "Thu", "Fri"],
  "values": [120, 200, 150, 310, 260]
}
```​
Key Meaning
type bar, hbar, line, area, pie, donut
labels x-axis / slice labels
values single series of numbers (≥ 0)
series instead of values: [{"name": "a", "values": […]}, …] — gives grouped bars / multi-line + legend (bar, line, area; hbar, pie and donut are single-series)
data instead of inline numbers: path to a .csv or .json file, relative to the deck (see below)
title optional caption above the chart
height optional SVG height (bar/line/area; default 280, minimum 80)
colorful hbar only: cycle the palette per bar

Charts from data files

```chart
{ "type": "bar", "title": "Outcomes by week", "data": "data/weekly.csv" }
```​

CSV format: a header row, then one row per label — first column is the labels, every other column becomes a series (one column → a single series, several → grouped bars / multi-line with a legend):

week,passed,failed
W1,58,6
W2,60,4

A .json data file is an object with labels and values (or series). Regenerate the file in CI and rebuild — the deck stays in sync with real output. serve watches *.csv / *.json next to the deck (and in data/) and reloads when they change. Don't mix data with inline labels/values/series — that's an error.

Charts become inline SVG using the theme's colors — they follow dark/light mode and print correctly. Worth knowing:

  • Negative values aren't supported.
  • Large numbers are abbreviated on axes and value labels: 1.2B, 3.5M, 150k.
  • hbar row labels longer than ~30 characters are truncated with an ellipsis — keep them short or use a table instead.
  • A bad spec (non-numeric value, unknown type, too-small height) fails the build with an error naming the slide; a label/value count mismatch builds but prints a warning.

Other blocks

```stats
63 | passed | green        ← value | label | color (green/amber/red/blue/gray)
```

```note Optional label
A highlighted callout box.
```

> **Or as a blockquote**
> First bold line becomes the note label.

```cards
### Card one
Splits on ### into a grid. Force columns with ```cards 3
### Card two

```

```pills
Link text | https://example.com     ← row of link chips
```

```python
any other fence tag = code block
```

```mermaid
graph TD; A-->B
```

The one exception to "no JS": if a deck contains a mermaid block, the output includes a CDN <script> so diagrams render — that page then needs network access. Everything else is fully offline.

Speaker notes

```notes
What to *say* on this slide — not what to show.
```

Notes are stripped from the output entirely by default. Build (or serve) with --notes and they render as dashed, clearly-marked boxes — so you can keep one source file and produce both a rehearsal copy and a clean shareable one. Add a label after the tag: ```notes Timing.

CLI

crosspresent demo                            build the bundled showcase deck and open it
    -t, --template sidebar|deck|doc          preview the demo in another template
    --notes                                  include the demo's speaker notes
    --no-open                                build but don't open the browser

crosspresent new <name> [--force]            scaffold a starter deck

crosspresent build <src.md> [<src.md> ...]   build each source to <src>.html
    -o, --output <path>                      choose output path (single source only)
    -d, --output-dir <dir>                   write every deck's .html into <dir>
    -t, --template sidebar|deck|doc          override the template
    --embed                                  inline local images as data URIs
    --notes                                  include speaker notes
    --open                                   open each result in a browser

crosspresent serve <src.md>                  live preview: save = auto-reload
    -t, --template sidebar|deck|doc          override the template
    --port <n>                               port (default 7350)
    --notes                                  include speaker notes
    --no-open                                don't open the browser

build accepts several sources or a glob — crosspresent build decks/*.md builds each next to its source, or all into one folder with --output-dir. A deck that fails (e.g. a bad chart) is reported but doesn't stop the rest; the command exits non-zero if any deck failed.

serve is a dev-mode preview: it builds in memory (nothing written to disk) and injects a tiny reload script — the only time crossPresent output contains JS you didn't ask for. build output is untouched.

Examples

File What it shows
examples/demo.md Every block type, one slide each

Exporting to PDF

Open the HTML in a browser and print — the print stylesheet hides the TOC and breaks one slide per page. (For the deck template, printing flows slides naturally instead of snap-scrolling.)

Tests

python3 -m unittest discover tests

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages