Markdown-driven interactive presentations β single binary, offline-first.
GoSlide turns .md files into Reveal.js presentations with live charts, diagrams, API dashboards, and interactive controls. No Node.js. No npm. Just one Go binary.
π δΈζη README
Download the latest release for your platform from GitHub Releases:
| Platform | File |
|---|---|
| Windows (x64) | goslide-windows-amd64.exe |
| macOS (Intel) | goslide-darwin-amd64 |
| macOS (Apple Silicon) | goslide-darwin-arm64 |
| Linux (x64) | goslide-linux-amd64 |
| Linux (ARM64) | goslide-linux-arm64 |
Rename to goslide (or goslide.exe on Windows), place in your PATH, and you're ready.
go install github.com/GMfatcat/goslide/cmd/goslide@latest# Create a presentation
goslide init
# Serve with live reload
goslide serve talk.md
# Export as standalone HTML
goslide build talk.md| Feature | Description |
|---|---|
| π Markdown authoring | Write slides in plain .md β frontmatter for config, --- for slide breaks |
| π¨ 22 themes | default, dark, corporate, minimal, hacker, dracula, midnight, gruvbox, solarized, catppuccin-mocha, ink-wash, instagram, western, pixel, nord-light, paper, catppuccin-latte, chalk, synthwave, forest, rose, amoled |
| π Charts | Bar, line, pie, radar, sparkline via Chart.js |
| π Diagrams | Mermaid.js flowcharts, sequence diagrams, ERD |
| π Tables | Sortable tables with click-to-sort headers |
| ποΈ Interactive controls | Tabs, sliders, toggles with reactive $variable binding |
| π Expandable cards | Grid layout with click-to-expand detail overlays |
| π API dashboards | Live data from backend APIs with auto-refresh |
| π API proxy | Built-in reverse proxy with auth header injection |
| π¦ Single binary | All assets embedded via go:embed (~8MB) |
| π Live reload | Edit .md β browser auto-refreshes, keeps slide position |
| π₯οΈ Speaker view | Press S for timer, notes, next slide preview |
| π€ Static export | goslide build β one .html file, works offline |
| π Host mode | Serve a directory as a presentation library |
| π‘ Presenter sync | Viewers see presenter's current slide + jump button |
22 built-in themes Γ 8 accent colors = 176 visual combinations.
---
theme: dracula
accent: pink
---π Full Theme Catalog
12 slide layouts via HTML comments:
---
<!-- layout: two-column -->
# Title
<!-- left -->
Left content
<!-- right -->
Right contentAvailable: default, title, section, two-column, code-preview, three-column, image-left, image-right, quote, split-heading, top-bottom, grid-cards, blank
Interactive components via fenced code blocks:
~~~chart:bar
title: Revenue
labels: ["Q1", "Q2", "Q3"]
data: [100, 150, 200]
color: teal
~~~goslide serve <file.md> # Serve with live reload
goslide host <directory> # Host multiple presentations
goslide build <file.md> # Export as standalone HTML
goslide init # Scaffold new presentation
goslide list [directory] # List presentationsπ Full CLI Reference
β οΈ Experimental. Output quality depends heavily on the chosen model and prompt. The generated Markdown is sanity-checked and auto-fixed for common syntax issues, but semantic quality (slide flow, accuracy, style) is not guaranteed. Review before presenting. API behavior and CLI flags may change without notice.
Generate a full presentation from a topic using any OpenAI-compatible LLM endpoint (OpenAI, OpenRouter, Ollama, vllm, sglang, etc.).
Add a generate: section to goslide.yaml:
generate:
base_url: https://api.openai.com/v1
model: gpt-4o
api_key_env: OPENAI_API_KEY
timeout: 120sExport the API key, then run:
export OPENAI_API_KEY=sk-...
goslide generate "Introduction to Kubernetes" # simple mode
goslide generate my-prompt.md -o talk.md # advanced mode
goslide generate --dump-prompt > system.txt # inspect promptAdvanced mode reads a prompt.md file:
---
topic: Kubernetes Architecture
audience: Backend engineers
slides: 15
theme: dark
language: en
---
Emphasize Pod/Service/Ingress. End with a Q&A slide.The command refuses to overwrite an existing output file unless --force is
passed. Generated Markdown is sanity-checked against the parser; common
issues (unclosed code fences, missing frontmatter terminator) are auto-fixed
with a transparent report.
Validated examples. See examples/ai-generated/
for real outputs (English + ηΉι«δΈζ, simple + advanced modes) produced by
openai/gpt-oss-120b:free on OpenRouter. Both parse on first pass. The
scripts/test-generate-llm.ps1 helper reproduces them.
When you don't have an image URL yet β either while drafting, or when a
presentation is produced by goslide generate β use the placeholder
component:
~~~placeholder
hint: K8s architecture
icon: πΊοΈ
aspect: 16:9
---
Control plane + worker node interaction
~~~
Combine several placeholders (or real images, charts, cards) with the
image-grid layout:
<!-- layout: image-grid -->
<!-- columns: 2 -->
<!-- cell -->
~~~placeholder
hint: Architecture
icon: πΊοΈ
~~~
<!-- cell -->

<!-- cell -->
~~~placeholder
hint: Trends
icon: π
~~~
<!-- cell -->
~~~chart
type: bar
...
~~~
Columns accept 2, 3, or 4. Each <!-- cell --> marks a new cell;
cells may hold any content.
The api component accepts a new render item of type llm. Fetched
JSON is substituted into a user-authored prompt via {{data}} and the
result renders inline:
~~~api
endpoint: /api/sales
render:
- type: chart:bar
label-key: quarter
data-key: revenue
- type: llm
prompt: |
Summarise these figures as 3 analyst bullets:
{{data}}
model: openai/gpt-oss-120b:free # optional; defaults to generate.model
~~~
- Cache-first. Same
(model, prompt, data)triplet only calls the LLM once; subsequent renders read from.goslide-cache/. - Click-to-call. On a cache miss in
goslide serve, viewers see aGenerate β¨button. No automatic LLM calls on page load. - Build-lock.
goslide buildinlines cached results into the static HTML. The exported deck never reaches an LLM at view time.
Reuses the generate: section of goslide.yaml β no new configuration.
For an offline build workflow, add fixture: ./data.json to the api
component; goslide build uses the fixture as the input data source
instead of calling the live endpoint.
goslide build --llm-refresh calls the LLM to populate missing cache
entries during the build. Without the flag, cache misses fail the
build and list the offending slides.
This feature is manual-author-only in v1.4.0. goslide generate does
not emit llm render items yet.
Export your deck as a PDF via headless Chrome:
goslide export-pdf talk.md
goslide export-pdf talk.md -o handout.pdf
goslide export-pdf talk.md --notes # include speaker notes
goslide export-pdf talk.md --paper-size a4-landscapePaper sizes: slide-16x9 (default), slide-4x3, a4-landscape,
letter-landscape.
Requires a locally-installed Chrome / Edge / Chromium (discovered via
PATH and standard install locations). Set GOSLIDE_CHROME_PATH to
point at a specific binary. No bundled Chromium β GoSlide stays a
single ~8MB binary.
Under the hood, export-pdf runs goslide build to produce a static
HTML, then drives Chrome's Page.printToPDF. Charts, Mermaid, themes,
and LLM-baked API results all render exactly as you see them in the
browser.
Optional goslide.yaml in the same directory as your .md file:
# API proxy β routes browser requests through Go server to upstream APIs
api:
proxy:
/api/backend:
target: http://localhost:8000
headers:
Authorization: "Bearer ${API_TOKEN}"
# Custom theme overrides
theme:
overrides:
slide-bg: "#1e1e2e"
slide-accent: "#f38ba8"Note: When
goslide.yamlhas proxy config, GoSlide will attempt to connect to the upstream targets on every proxied request. If an upstream is not running, you'll seeproxy errorin the console and 502 responses in the browser β this only affects API component slides, not the rest of your presentation.
GoSlide includes a mock API server for testing API-driven slides:
# Terminal 1: Start mock API server
go run examples/mock-api/main.go
# β Mock API running on http://localhost:9999
# Terminal 2: Copy the example config and serve
cp examples/goslide.yaml.example examples/goslide.yaml
go run ./cmd/goslide serve examples/demo.md --no-open
# β Open http://localhost:3000, navigate to API Dashboard slidesThe example config (goslide.yaml.example) proxies /api/mock to localhost:9999. Rename it to goslide.yaml to activate. When done testing, you can remove or rename the config to avoid proxy errors when the mock server isn't running.
GoSlide has a lightweight presenter sync feature. The presenter's current slide is broadcast to all viewers in real-time.
Presenter opens with ?role=presenter:
http://localhost:3000?role=presenter
Viewers open the normal URL:
http://localhost:3000
When the presenter navigates slides, viewers see a small indicator at the bottom-left:
ββββββββββββββββββββββββββββ
β Presenter: 5/12 [Jump] β
ββββββββββββββββββββββββββββ
- Viewers can click Jump to go to the presenter's current slide
- Viewers can freely browse on their own β they are never forced to follow
- Works in both
serveandhostmode
Press S on any slide to open the speaker view in a new window. It shows:
- Current slide + next slide preview
- Speaker notes (from
<!-- notes -->in your markdown) - Elapsed time
git clone https://github.com/GMfatcat/goslide.git
cd goslide
bash scripts/vendor.sh --update-checksums
go build -o goslide ./cmd/goslideRequirements: Go 1.21+
---
transition: perspective # 3D Y-axis rotation
---Available: slide (default), fade, convex, concave, zoom, none, perspective, flip
# My Slide
Content here.
<!-- notes -->
Speaker notes β visible in speaker view (press S).GoSlide is built on the shoulders of these excellent open-source projects:
| Project | Role | License |
|---|---|---|
| Reveal.js | Slide rendering engine | MIT |
| Chart.js | Charts (bar, line, pie, radar, sparkline) | MIT |
| Mermaid | Diagrams (flowcharts, sequence, ERD) | MIT |
| goldmark | Markdown parser | MIT |
| cobra | CLI framework | Apache-2.0 |
| fsnotify | File system watcher | BSD-3 |
| coder/websocket | WebSocket library | MIT |
| Noto Sans TC | CJK font | OFL-1.1 |
| JetBrains Mono | Monospace font | OFL-1.1 |
| Press Start 2P | Pixel font (pixel theme) | OFL-1.1 |
| Rye | Western font (western theme) | OFL-1.1 |
Theme color palettes inspired by: Dracula, Catppuccin, Gruvbox, Solarized, Nord.
MIT