Toboggan
Toboggan is a modern, multi-platform presentation system built in Rust. Write your slides in Markdown or TOML, serve them via a WebSocket-enabled server, and present from any client — web browser, terminal, desktop app, or mobile device.
Inspiration
The name Toboggan comes from the French word for slides (as in a slide deck). It's a project originally started by Igor Labori (@ilaborie), which I took over to advance and evolve into the multi-platform system it is today.
Inspired by the Italian animated series Huntik, Toboggan lets you become a Seeker of knowledge. Your presentations are your Titans — powerful, dynamic, and under your control.
Features
- Simple content creation — Write presentations in Markdown or TOML
- Real-time synchronization — Multi-client sync via WebSocket
- Multi-platform clients — Web, terminal, desktop, iOS, embedded
- Zero external dependencies — Just a single binary per component
Quick start
# 1. Start the server with a presentation
toboggan-server examples/demo.toml
# 2. Open the web UI
# → http://localhost:8080
# 3. Control from the terminal
toboggan-tui http://localhost:8080
Installation
Download pre-built binaries
Get the latest release from github.com/Tednoob17/toboggan/releases.
Each file is named by platform:
| File | Platform |
|---|---|
toboggan-cli-linux-amd64 | Linux x86_64 |
toboggan-server-linux-amd64 | Linux x86_64 |
toboggan-tui-linux-amd64 | Linux x86_64 |
toboggan-desktop-linux-amd64 | Linux x86_64 (desktop GUI) |
*macos-amd64 | macOS (Intel) |
*macos-arm64 | macOS (Apple Silicon) |
*windows-amd64.exe | Windows x86_64 |
*.deb | Debian / Ubuntu packages |
Linux
# Download
curl -sSfL https://github.com/Tednoob17/toboggan/releases/latest/download/toboggan-cli-linux-amd64 -o toboggan-cli
# Make executable and install
chmod +x toboggan-cli
sudo mv toboggan-cli /usr/local/bin/
Repeat for toboggan-server, toboggan-tui, and toboggan-desktop as needed.
macOS
# Intel Mac
curl -sSfL https://github.com/Tednoob17/toboggan/releases/latest/download/toboggan-cli-macos-amd64 -o toboggan-cli
# Apple Silicon Mac
curl -sSfL https://github.com/Tednoob17/toboggan/releases/latest/download/toboggan-cli-macos-arm64 -o toboggan-cli
chmod +x toboggan-cli
sudo mv toboggan-cli /usr/local/bin/
Windows (PowerShell)
curl.exe -sSfL https://github.com/Tednoob17/toboggan/releases/latest/download/toboggan-cli-windows-amd64.exe -o toboggan-cli.exe
# Move to a directory in your PATH
Debian / Ubuntu
curl -sSfL https://github.com/Tednoob17/toboggan/releases/latest/download/toboggan-cli-linux-amd64.deb -o toboggan-cli.deb
sudo dpkg -i toboggan-cli.deb
Build from source
Requires Rust (stable).
# Clone
git clone https://github.com/Tednoob17/toboggan
cd toboggan
# Build main workspace (CLI + server + TUI)
cargo build --release
# Build desktop app (separate workspace)
cargo build --release --manifest-path toboggan-desktop/Cargo.toml
Binaries are in target/release/.
Creating Presentations
Presentations in Toboggan are written in TOML format. You can also write slides in Markdown and convert them with the CLI.
Step-by-step: create your first presentation
1. Create a new file
touch my-talk.toml
2. Write the presentation header
[presentation]
title = "My First Talk"
author = "Your Name"
description = "A demo presentation for Toboggan"
This section defines the overall presentation metadata.
3. Add slides
Each slide is a [[slides]] entry. Slides appear in the order you write them.
[[slides]]
kind = "Part"
title = "Introduction"
A Part slide acts as a section divider.
[[slides]]
title = "Welcome!"
body = '''
This is my first slide.
Toboggan supports **bold**, *italic*, and `code` in Markdown.
'''
4. Add more slides
[[slides]]
title = "Key Points"
body = '''
- First point
- Second point
- Third point
'''
[[slides]]
title = "Code Demo"
body = '''
Here is some Rust code:
```rust
fn hello() {
println!("Hello Toboggan!");
}
```
'''
[[slides]]
title = "Thanks!"
body = "Thank you for watching!"
5. Run the server
toboggan-server my-talk.toml
Open http://localhost:8080 in your browser to see your presentation.
Full example
[presentation]
title = "My Talk"
author = "Your Name"
description = "A short description"
[[slides]]
kind = "Part"
title = "Part 1"
[[slides]]
title = "Welcome!"
body = "Hello world!"
[[slides]]
title = "Styled Slide"
[slides.style]
background_color = "#2d3436"
color = "#dfe6e9"
[[slides]]
kind = "Part"
title = "Part 2"
[[slides]]
title = "With Notes"
body = "Slide content here"
[slides.notes]
body = "Speaker notes — only visible in presenter mode"
Slide fields
| Field | Type | Required | Description |
|---|---|---|---|
kind | string | No | "Slide" (default) or "Part" |
title | string | Yes | Slide title |
body | string | No | Markdown content |
duration | duration | No | Auto-advance time (e.g. "30s", "2m") |
Style fields
| Field | Type | Description |
|---|---|---|
background_color | string | CSS color for background |
color | string | CSS color for text |
font_size | integer | Font size in pixels |
Notes
[slides.notes]
body = "Your speaker notes here"
Notes are visible in presenter mode and are not shown to the audience.
Converting Markdown to TOML
If you prefer writing in Markdown:
# Convert a folder of markdown files to TOML
toboggan-cli slides/ -f toml -o presentation.toml
Your folder structure:
slides/
├── 01-intro.md
├── 02-details.md
└── 03-end.md
Each Markdown file becomes a slide. The frontmatter of each file sets the slide metadata:
---
title: "My Slide"
duration = "1m"
---
Slide content here...
CLI Usage
The CLI (toboggan-cli) converts Markdown presentations to TOML format.
Basic usage
# Convert a markdown presentation to TOML
toboggan-cli slides/ -f toml -o presentation.toml
# Convert to HTML (standalone)
toboggan-cli slides/ -f html -o presentation.html
# Show statistics about a presentation
toboggan-cli slides/ --stats
Commands
| Command | Description |
|---|---|
slides/ | Path to a file or directory of markdown slides |
-f, --format | Output format: toml, html, stat |
-o, --output | Output file path |
--stats | Show slide statistics |
--export-pdf | Export to PDF (requires headless Chrome) |
Folder structure
slides/
├── 01-introduction.md
├── 02-concepts.md
│ └── 02-subtopic.md
└── 03-conclusion.md
Each markdown file becomes a slide. Folders can be used for nesting.
Markdown frontmatter
---
title: "Slide Title"
duration = "5m"
style = { background_color = "#fff", color = "#333" }
---
Slide content here...
Server Usage
The server (toboggan-server) hosts your presentation and synchronizes
all connected clients in real time via WebSocket.
Starting the server
# Basic usage
toboggan-server presentation.toml
# Custom port
toboggan-server --port 9090 presentation.toml
# With hot reload (watch for file changes)
toboggan-server --watch presentation.toml
Connecting clients
Once the server is running, open any client and point it to the server URL:
| Client | Command / URL |
|---|---|
| Web | http://localhost:8080 |
| TUI | toboggan-tui http://localhost:8080 |
| Desktop | Launches and auto-connects |
API endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/talk | GET | Get current talk state |
/api/command | POST | Send a command (NextSlide, PrevSlide, GotoSlide, etc.) |
/api/commands | POST | Send multiple commands at once |
/ws | WebSocket | Real-time sync and notifications |
/doc | GET | Interactive API documentation (Scalar UI) |
Available commands
{ "command": "NextSlide" }
{ "command": "PrevSlide" }
{ "command": "GotoSlide", "params": { "index": 0 } }
Systemd service (Linux)
[Unit]
Description=Toboggan Presentation Server
After=network.target
[Service]
ExecStart=/usr/local/bin/toboggan-server /path/to/presentation.toml
Restart=on-failure
User=youruser
[Install]
WantedBy=multi-user.target
Desktop App
The desktop app (toboggan-desktop) provides a graphical user interface
built with Iced and wgpu.
Running
# Launch the desktop app
toboggan-desktop
# It will auto-connect to localhost:8080
# Start the server first, then launch the desktop
Workflow
- Start the server:
toboggan-server my-talk.toml - Launch the desktop:
toboggan-desktop - The desktop connects to the server automatically
- Use the desktop to navigate slides
Known behavior
- The desktop app will show "Connection refused" errors if the server is not running — this is normal. Start the server first.
- Built-in GPU-accelerated rendering via Vulkan/OpenGL.
Requirements
- Linux:
libxkbcommon-dev,libwayland-dev,libegl1-mesa-dev,libgles2-mesa-dev - RAM: ~4 GB during compilation, ~128 MB at runtime
TUI Client
The terminal UI client (toboggan-tui) allows you to view and control
presentations from the terminal, using Ratatui.
Running
# Connect to a running server
toboggan-tui http://localhost:8080
Controls
| Key | Action |
|---|---|
→ / n | Next slide |
← / p | Previous slide |
q / Ctrl+C | Quit |
g | Go to slide (type number) |
r | Refresh / reconnect |
? | Toggle help |
Features
- Real-time slide display with syntax highlighting
- Speaker notes view (with presenter mode)
- Connection status indicator
- Works over SSH — present remotely from any terminal
Example
# On the presentation machine
toboggan-server talk.toml
# On any machine connected to the same network
toboggan-tui http://192.168.1.42:8080
Web Client
The web client provides a browser-based interface for viewing and controlling presentations.
Accessing
Start the server, then open your browser:
http://localhost:8080
Features
- Real-time slide display with CSS transitions
- Navigation controls (next/previous/goto)
- Remote control from any device (phone, tablet, laptop)
- Presenter mode with speaker notes
Presenter view
Access the presenter view at /presenter:
http://localhost:8080/presenter
This shows the current slide, next slide preview, speaker notes, and a timer.
Kiosk mode
For full-screen public displays:
http://localhost:8080/kiosk
- Hides navigation UI
- Auto-advances slides
- Perfect for projectors and digital signage
Presenting from Any Device
Toboggan's real-time synchronization lets you control presentations from any device on the same network — phone, tablet, laptop, or another computer.
How it works
- Start the server on your main machine
- Find your machine's IP address
- Open any client on any device and point it to the server
Finding your IP
# Linux
ip addr show | grep "inet " | grep -v 127.0.0.1
# macOS
ifconfig | grep "inet " | grep -v 127.0.0.1
# Windows (PowerShell)
ipconfig | findstr "IPv4"
Typically looks like 192.168.1.42 or 10.0.0.5.
Connecting from different devices
From another computer (same network)
# Terminal (TUI)
toboggan-tui http://192.168.1.42:8080
# No installation needed — use the web UI
# Just open a browser to:
http://192.168.1.42:8080
From a phone or tablet
No app needed! Just open the browser and navigate to:
http://192.168.1.42:8080
This works on iPhone, iPad, Android, and any smartphone.
From iOS (native app)
The toboggan-mobile crate provides native iOS bindings via UniFFI.
Build the Xcode project and run on your iPhone/iPad.
From the internet (not just local network)
To present over the internet, you need to expose the server:
Option A — SSH tunnel (secure, no config)
# On a public server
ssh -R 8080:localhost:8080 user@your-server.com
# Then access from anywhere:
http://your-server.com:8080
Option B — ngrok (quick)
ngrok http 8080
# Then share the ngrok URL with anyone
Option C — Deploy to a VPS
# On your VPS with a public IP
toboggan-server --port 8080 --access-token "my-secret" talk.toml
Then access from anywhere: http://your-vps-ip:8080
Multiple viewers
Toboggan supports unlimited concurrent viewers. Everyone connected to the server sees the same slide in real time. Perfect for:
- Classroom teaching
- Conference presentations
- Remote team meetings
Presentation Format
The TOML presentation format is the native format for Toboggan.
Full example
[presentation]
title = "My Talk"
author = "Jane Doe"
description = "An example presentation"
version = "0.1.0"
[[slides]]
kind = "Part"
title = "Part 1: Introduction"
[[slides]]
title = "Welcome"
body = '''
Welcome to this presentation!
This is a multi-line text block.
'''
[slides.style]
background_color = "#2d3436"
color = "#dfe6e9"
[[slides.notes]]
body = "Speaker notes go here"
[[slides]]
title = "Code Example"
body = '''
Here is some Rust code:
```rust
fn hello() {
println!("Hello!");
}
```
'''
[[slides]]
kind = "Part"
title = "Part 2: Deep Dive"
[[slides]]
title = "Key Concepts"
body = '''
- First concept
- Second concept
- Third concept
'''
Field reference
Presentation
| Field | Type | Required | Description |
|---|---|---|---|
title | String | Yes | Presentation title |
author | String | No | Author name |
description | String | No | Short description |
Slide
| Field | Type | Required | Description |
|---|---|---|---|
kind | String | No | "Slide" (default) or "Part" |
title | String | Yes | Slide title |
body | String | No | Slide body content (Markdown) |
duration | Duration | No | Auto-advance timer |
Style
| Field | Type | Description |
|---|---|---|
background_color | String | CSS color |
color | String | Text color |
font_size | Integer | Font size in pixels |
Duration format
Durations can be specified as:
| Format | Example | Result |
|---|---|---|
| Seconds | 30s | 30 seconds |
| Minutes | 2m | 2 minutes |
| Hours | 1h | 1 hour |
| Combined | 1m 30s | 1 minute 30 seconds |
Configuration
Server configuration
The server accepts command-line arguments:
toboggan-server [OPTIONS] <PRESENTATION>
Options:
-p, --port <PORT> Server port [default: 8080]
-w, --watch Watch for file changes
--watch-delay <MS> Watch debounce delay [default: 200]
--access-token <TOKEN> Require token for API access
--heartbeat <SECS> Heartbeat interval [default: 30]
--cleanup <SECS> Cleanup interval [default: 30]
--shutdown <SECS> Shutdown timeout [default: 10]
-h, --help Print help
-V, --version Print version
Environment variables
| Variable | Description |
|---|---|
TOBOGGAN_SKIP_WEB_CHECK=1 | Skip web dist check at build time |
RUST_LOG=toboggan_server=debug | Enable debug logging |
Retry configuration
The client reconnection behavior can be configured in the presentation
file via the [client] section:
[client]
max_retries = 10
initial_retry_delay = "1s"
max_retry_delay = "30s"
backoff_factor = 2.0
Logging
Toboggan uses the env_logger crate. Set RUST_LOG to control verbosity:
RUST_LOG=info toboggan-server talk.toml
RUST_LOG=toboggan_server=debug toboggan-server talk.toml
RUST_LOG=toboggan_client=trace toboggan-tui http://localhost:8080
Architecture
Toboggan is organized as a Rust workspace with multiple crates:

| Crate | Role |
|---|---|
toboggan-core | Core types & no_std logic |
toboggan-server | Axum WebSocket server (talk state owner) |
toboggan-cli | Markdown → TOML conversion |
toboggan-client | Shared WebSocket client library |
toboggan-tui | Terminal UI (Ratatui) |
toboggan-web | Web frontend (TypeScript + WASM) |
toboggan-desktop | Desktop app (Iced + wgpu, separate workspace) |
toboggan-mobile | iOS bindings (UniFFI) |
toboggan-stats | Presentation statistics |
toboggan-esp32 | ESP32 embedded client |
Key design decisions
toboggan-coreisno_stdcompatible, usable from embedded devices- Server owns the talk state and broadcasts changes to all clients
- Clients are stateless — they display what the server sends
- Protocol is WebSocket for real-time, REST for batch operations
- Desktop is a separate workspace to reduce build RAM usage
Protocol
The WebSocket protocol uses JSON messages:
// Server → Client
{ "type": "state", "state": { "current": 0, "total": 10 } }
{ "type": "slide", "index": 0, "content": { "title": "...", "body": "..." } }
// Client → Server
{ "type": "command", "command": "NextSlide" }
{ "type": "ping" }
// Server → Client
{ "type": "pong" }
{ "type": "error", "message": "..." }