WorshipKit Slides — Import, Edit, Export — also available as raw markdown. AI agents can discover this via /llms.txt.

WorshipKit Slides — Importing, Editing, and Exporting

A guide to /slides — the SPA that turns Word / Pages / PowerPoint documents into ProPresenter slides, lets a church team edit them in the browser, and exports them as .proBundle (or .pro, .pptx, .key).

Public URL: https://worshipkit.com/slides-editor Also served as raw Markdown at: https://worshipkit.com/slides-editor.md

If you're an AI agent helping a WorshipKit user prepare slides, read this whole page — it covers the two import paths, how the editor represents styling, and the export formats.


The two import paths

Every document that ends up in /slides/editor/:id came through one of two paths. Both apply the user's active Design (from /slides/designs) — the same Design decides slide chunking, reference extraction, and per-run styling on either path.

1. Quick Import — one shot from source to editor

Drop a .docx / .pages / .pptx on the Documents dropzone (or click Quick Import). The server:

1. Runs the file through pp7gen's DocumentProcessor with the Design's rules payload — the rules engine chunks paragraphs, extracts Bible references, splits long passages at sentence boundaries, interleaves blank slides, and applies per-run styling. 2. Hands the resulting slides to pp7gen's Generator, which emits a ProPresenter .pro protobuf. 3. Persists it as a SlideDocument (id-scoped to the user's organization). 4. Redirects the browser to /slides/editor/:id.

Use Quick Import when the Design is trusted and the source doc is well-formatted — no review step, straight to the editable slides.

2. Draft Review — human-in-the-loop before slide generation

Drop the same file on the dropzone and pick either Continue without AI (legacy path — the rules engine returns raw slides for review) or one of the AI prompts. The SPA:

1. Posts to POST /documents/legacy_draft (or ai_draft) — server runs the rules engine but returns the parsed slide list as JSON instead of generating a .pro. 2. Renders each slide as a thumbnail in DraftReviewPage; the user can edit body text, add / remove slides, and toggle "blank slides between chunks." 3. On Generate, the SPA posts the reviewed slides to POST /documents/generate_from_draft — the server runs the Generator and creates the SlideDocument.

Use Draft Review when the source is a rough transcript, the design rules are new, or when the user wants to fix chunking before generating slides.

Both paths share


The Slides editor (EditorPage)

Open a document at /slides/editor/:id. The layout is three panes:

Inline text editing

Double-click a text element. The element becomes a contentEditable with per-run styling preserved:

FloatingFormatBar

While editing, a small toolbar floats above the element with B / I / U buttons. They wrap the current selection in <b> / <i> / <u> and round-trip back through \b / \i / \ul toggles in the RTF.

Per-slide edits (not text)

The right-hand EditorPanel handles:

Every change goes through handlePresentationChange, which debounces a save at 500ms. The last-saved state is what a re-open loads.


Exporting a document

Three formats are exposed from /slides/editor/:id:

FormatEndpointContents
.proBundleGET /api/v2/documents/:id/download?format=probundleZip of the .pro protobuf + Media/Assets/ — what ProPresenter opens
.proGET /api/v2/documents/:id/download?format=proJust the .pro protobuf (no bundled media)
.pptxGET /api/v2/documents/:id/download?format=pptxPowerPoint (best-effort text extraction)
.keyGET /api/v2/documents/:id/download?format=keyKeynote (best-effort text extraction)

All formats route through DocumentExportDispatcher, which:

1. Decodes the stored protobuf (or the in-progress JSON if the SPA sends presentation_json). 2. Applies workspace themes + per-cue metadata via DownloadPresentationBuilder. 3. Runs PresentationHealer.heal! — UUID normalization, RTF Cocoa-shape validation, colortbl / expandedcolortbl slot alignment, notes wrapping, opacity / geometry defaults. 4. Hands the final Rv::Data::Presentation to the format strategy's write method.

Getting the download from the SPA

The editor's overflow menu → Download picks the format. The SPA posts the current in-memory presentation as presentation_json so even unsaved edits ship with the download.

Automated exports (agents + scripts)

Every /api/v2/documents/* endpoint requires a Bearer token in the Authorization header. Two token types work — same as the Billboard API:

Missing / invalid auth returns HTTP 401 with Content-Type: application/json, body {"error":"Unauthorized"}, and a WWW-Authenticate: Bearer realm="worshipkit" header — an agent can detect the auth failure programmatically from any of those signals. A HTTP 404 means the document doesn't exist (or was soft-deleted, or belongs to another organization).

Common endpoints:


# List every document in the user's organization.
GET /api/v2/documents

# Fetch one document (JSON metadata + presentation_json payload).
GET /api/v2/documents/:id

# Rename it.
PUT /api/v2/documents/:id
    { "name": "Renamed" }

# Download the .proBundle for ProPresenter.
GET /api/v2/documents/:id/download?format=probundle
GET /api/v2/documents/:id/download?format=pro
GET /api/v2/documents/:id/download?format=pptx
GET /api/v2/documents/:id/download?format=key

# Import a source doc (Quick Import path).
POST /api/v2/documents/import
     Content-Type: multipart/form-data
     [email protected]
     design_id=42        # optional; picks a specific Design

# Draft-review path (returns slides for review before generation).
POST /api/v2/documents/legacy_draft
     Content-Type: multipart/form-data
     [email protected]
     design_id=42

# Generate a document from an approved draft (SPA + agent both use this).
POST /api/v2/documents/generate_from_draft
     Content-Type: multipart/form-data
     draft={"name":"…","slides":[…]}
     images={"filename.jpg":"<base64>", …}
     design_id=42
     add_blank_slides=true

# Soft-delete a document.
DELETE /api/v2/documents/:id

Concrete example — export the current .proBundle:


curl -H 'Authorization: Bearer wk_pat_abc123…' \
     -o slides.proBundle \
     'https://worshipkit.com/api/v2/documents/123/download?format=probundle'

Concrete example — import a Word doc using Design #42, get the new document id back:


curl -H 'Authorization: Bearer wk_pat_abc123…' \
     -F '[email protected]' \
     -F 'design_id=42' \
     'https://worshipkit.com/api/v2/documents/import'

The response is JSON: {"id": 456, "name": "sermon", "updated_at": "…", …}.


Importing a ProPresenter file

/slides/import accepts .pptx, .key, .pro, and .proBundle. Non-source formats (.pro, .proBundle) go through ::Slides::PresentationImporter — the presentation lands in /slides/editor/:id without a rules-engine pass, so it opens exactly as ProPresenter would render it (text, colors, fonts, per-run styling from the source .pro all preserved).

Use this path when a user already has slides they want to edit in the browser rather than in ProPresenter.


Notes for AI agents


Where this lives