Files
deckcraft/apps/deckcraft-web/src/main.rs
T
bradandClaude Opus 5.5 d5471bccf0 Web: open and save through a framing page (?host=parent)
A same-origin page that frames DeckCraft's web build with ?host=parent
sends a file with deckcraft:open and gets every save back as
deckcraft:save {name, saveAs, bytes} instead of a download, with
deckcraft:ready, deckcraft:dirty and deckcraft:failed, as GridCraft,
WordCraft and PdfCraft do. Without ?host=parent nothing changes.

Save follows the desktop app. Every file from the page opens through
file.adopt like File > Open on the desktop; a presentation sent with a
presentation name keeps that name as its file, so Save (Ctrl+S, the
File tab, the Close prompt or the command palette) writes it back under
that name and format with saveAs: false. Anything else (no name, an
outline, a damaged file opened as a repaired copy, a dropped file) is
untitled, and its first Save is a new <title>.deckcraft with saveAs:
true, as is Save As. Exports and Print are copies (saveAs: false).

Host mode starts with an empty presentation that gives way to the first
file while untouched, &author= signs comments, and the URL flags are
read as whole parameters so a free-text author can't set ?show.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 18:58:29 -06:00

40 lines
1.7 KiB
Rust

//! DeckCraft in the browser.
//!
//! Runs the same [`deckcraft_ui_egui::SlideApp`] as the desktop app through eframe's web
//! runner (wgpu: WebGPU where available, WebGL2 otherwise). Build with `trunk build --release`
//! from this directory (output in `dist/web`).
//!
//! Differences from the desktop app:
//! - no TCP control channel (browsers can't listen on sockets);
//! - File → Open and Insert → Pictures/Audio/Video use the browser file picker; bytes arrive
//! asynchronously through `Services::inbox`, applied to the document, slide and operation
//! that started the pick (a dismissed picker or a closed document drops the file);
//! - Save and Export trigger a browser download (or go to the framing page with `?host=parent`);
//! - dropped files are read asynchronously by `web::WebShell` and delivered through the inbox;
//! - preferences are not persisted.
//!
//! URL query flags: `?webgl` forces the WebGL2 backend instead of WebGPU; `?blank` starts with an
//! empty presentation instead of the sample deck; `?show` starts the slide show.
//! `?host=parent` (inside an `<iframe>`) talks to a same-origin parent page instead: it sends the
//! presentation to open and stores what DeckCraft saves (`host`), and `&author=` names the user
//! for comments.
#![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
#![forbid(unsafe_code)]
#[cfg(target_arch = "wasm32")]
mod host;
#[cfg(target_arch = "wasm32")]
mod presenter;
#[cfg(target_arch = "wasm32")]
mod web;
#[cfg(target_arch = "wasm32")]
fn main() {
web::start();
}
#[cfg(not(target_arch = "wasm32"))]
fn main() {
eprintln!("deckcraft-web only runs in the browser: build it with `trunk build --release` in apps/deckcraft-web");
}