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 active Design's
add_blank_slidesandsplit_long_textoptions. - Media (images embedded in the source doc) is base64'd into the draft round-trip and stored as
SlideDocumentMediaItemrows. - The generated
.procarries every slide'stype(fromset_slide_typerules) into the ProPresenter cue so downstream style rules and themes can key on it.
The Slides editor (EditorPage)
Open a document at /slides/editor/:id. The layout is three panes:
- Left (thumbnails): every cue in the presentation, drag-to- reorder, right-click menu for duplicate / hide / delete / theme.
- Center (SlideCanvas): the selected slide scaled to fit the viewport. Click an element to select it; double-click a text element to edit inline.
- Right (EditorPanel): per-slide + per-element controls (text color, font size, alignment, timer, theme override, hot key, notes).
Inline text editing
Double-click a text element. The element becomes a contentEditable with per-run styling preserved:
- Bold / italic / underline stay visible during edit and round-trip back through the RTF on blur.
- Per-run color and font_family (Rules::StylePass emphasis like Black Diamond Fixed gold on a bold+underline word) are wrapped in inline-style spans during edit. Typing inside an emphasized run inherits its styling; typing outside it inherits the surrounding element font.
- Enter inserts a newline. Escape exits without saving. Blur saves.
- A no-op edit (double-click and click away without changing text or modifiers) does NOT trigger a save — per-run styling is preserved exactly.
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:
- Slide-level: background color, notes, hot key, "advance after N seconds" timer, workspace theme override.
- Element-level: move / resize (drag corners in the canvas), text color picker, font size, alignment, delete.
- Cue metadata (hot key, timer, notes, theme override) is stored server-side in
CueMetarows and re-woven into the protobuf on export byDownloadPresentationBuilder.
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:
| Format | Endpoint | Contents |
|---|---|---|
.proBundle | GET /api/v2/documents/:id/download?format=probundle | Zip of the .pro protobuf + Media/Assets/ — what ProPresenter opens |
.pro | GET /api/v2/documents/:id/download?format=pro | Just the .pro protobuf (no bundled media) |
.pptx | GET /api/v2/documents/:id/download?format=pptx | PowerPoint (best-effort text extraction) |
.key | GET /api/v2/documents/:id/download?format=key | Keynote (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:
- Personal Access Token (PAT) — created by a signed-in user in the browser at /settings/api-tokens (accessible from the user menu → Your Profile → *"Manage API tokens →"*). Give the token a descriptive name (e.g. the agent it's for), copy the raw string on the reveal panel (this is the only time it will be visible), and paste it into your agent's config as the
Authorization: Bearer <token>value. Scope: everything the user can do — read + write every document their organization owns. Revoke from the same page when you rotate. Scripted alternative:POST /api_tokens { "name": "…" }returns the raw token in the response envelope, but the browser flow is the recommended path for humans setting up an agent. - Doorkeeper OAuth token — issued by the standard OAuth2 flow at
/oauth/authorize. Scoped.
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
- The Design (from
/slides/designs) is the authority on how a document becomes slides. Point users there first if their import chunks or styles look wrong. - Editor edits change the
.proin place — they never re-run the rules engine. Re-importing the source doc is the only way to re-apply Design changes to an existing document. - Per-run styling (color, font, bold/italic/underline) survives inline edits, but per-run color and font_family can only be set by a Design's Text rule at import time (there's no editor UI for a color / font picker on a text sub-selection today — users pick element-level colors from EditorPanel).
- ProPresenter's slide-list thumbnail sometimes falls back to the element's
text_solid_filland paints per-run color runs white, even though the same slide plays back correctly. That's a PP render cache; not a WK export bug. Suggest closing and reopening the presentation in PP if the thumbnail is misleading.
Where this lives
- Source of truth:
docs/slides_editor.mdin the WorshipKit web repo. - Served publicly at:
/slides-editor(HTML) and/slides-editor.md(raw markdown). - Discovered by AI agents via:
/llms.txtat the site root.