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:

FilePlatform
toboggan-cli-linux-amd64Linux x86_64
toboggan-server-linux-amd64Linux x86_64
toboggan-tui-linux-amd64Linux x86_64
toboggan-desktop-linux-amd64Linux x86_64 (desktop GUI)
*macos-amd64macOS (Intel)
*macos-arm64macOS (Apple Silicon)
*windows-amd64.exeWindows x86_64
*.debDebian / 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

FieldTypeRequiredDescription
kindstringNo"Slide" (default) or "Part"
titlestringYesSlide title
bodystringNoMarkdown content
durationdurationNoAuto-advance time (e.g. "30s", "2m")

Style fields

FieldTypeDescription
background_colorstringCSS color for background
colorstringCSS color for text
font_sizeintegerFont 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

CommandDescription
slides/Path to a file or directory of markdown slides
-f, --formatOutput format: toml, html, stat
-o, --outputOutput file path
--statsShow slide statistics
--export-pdfExport 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:

ClientCommand / URL
Webhttp://localhost:8080
TUItoboggan-tui http://localhost:8080
DesktopLaunches and auto-connects

API endpoints

EndpointMethodDescription
/api/talkGETGet current talk state
/api/commandPOSTSend a command (NextSlide, PrevSlide, GotoSlide, etc.)
/api/commandsPOSTSend multiple commands at once
/wsWebSocketReal-time sync and notifications
/docGETInteractive 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

  1. Start the server: toboggan-server my-talk.toml
  2. Launch the desktop: toboggan-desktop
  3. The desktop connects to the server automatically
  4. 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

KeyAction
/ nNext slide
/ pPrevious slide
q / Ctrl+CQuit
gGo to slide (type number)
rRefresh / 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

  1. Start the server on your main machine
  2. Find your machine's IP address
  3. 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

FieldTypeRequiredDescription
titleStringYesPresentation title
authorStringNoAuthor name
descriptionStringNoShort description

Slide

FieldTypeRequiredDescription
kindStringNo"Slide" (default) or "Part"
titleStringYesSlide title
bodyStringNoSlide body content (Markdown)
durationDurationNoAuto-advance timer

Style

FieldTypeDescription
background_colorStringCSS color
colorStringText color
font_sizeIntegerFont size in pixels

Duration format

Durations can be specified as:

FormatExampleResult
Seconds30s30 seconds
Minutes2m2 minutes
Hours1h1 hour
Combined1m 30s1 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

VariableDescription
TOBOGGAN_SKIP_WEB_CHECK=1Skip web dist check at build time
RUST_LOG=toboggan_server=debugEnable 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:

Toboggan architecture diagram

CrateRole
toboggan-coreCore types & no_std logic
toboggan-serverAxum WebSocket server (talk state owner)
toboggan-cliMarkdown → TOML conversion
toboggan-clientShared WebSocket client library
toboggan-tuiTerminal UI (Ratatui)
toboggan-webWeb frontend (TypeScript + WASM)
toboggan-desktopDesktop app (Iced + wgpu, separate workspace)
toboggan-mobileiOS bindings (UniFFI)
toboggan-statsPresentation statistics
toboggan-esp32ESP32 embedded client

Key design decisions

  • toboggan-core is no_std compatible, 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": "..." }