diff --git a/Cargo.lock b/Cargo.lock index 3c34e0f6..efa9b978 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,6 +18,7 @@ version = "0.5.7" dependencies = [ "acadrust", "bytemuck", + "console_error_panic_hook", "cosmic-text", "flate2", "fontdb", @@ -977,6 +978,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "convert_case" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index fae4e8e2..15a5c814 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,3 +79,6 @@ acadrust = { git = "https://github.com/HakanSeven12/acadrust", branch = "main" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] open = "5" ureq = { version = "3", default-features = false, features = ["rustls"] } + +[target.'cfg(target_arch = "wasm32")'.dependencies] +console_error_panic_hook = "0.1" diff --git a/Trunk.toml b/Trunk.toml new file mode 100644 index 00000000..e58869cd --- /dev/null +++ b/Trunk.toml @@ -0,0 +1,16 @@ +# Trunk config for the web (wasm) build of Open CAD Studio (issue #45). +# +# Build: trunk build --release +# Dev: trunk serve +# +# Requires: rustup target add wasm32-unknown-unknown +# cargo install trunk wasm-bindgen-cli + +[build] +target = "index.html" + +[serve] +# Cross-origin isolation headers enable SharedArrayBuffer, which wasm threads +# (rayon) need. GitHub Pages cannot set these; a self-hosted server (e.g. the +# Open-AEC host) can. Without them the app still runs single-threaded. +headers = { "Cross-Origin-Opener-Policy" = "same-origin", "Cross-Origin-Embedder-Policy" = "require-corp" } diff --git a/index.html b/index.html new file mode 100644 index 00000000..a58c5347 --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + + + Open CAD Studio + + + + + + diff --git a/src/app/mod.rs b/src/app/mod.rs index ae19fe7e..67b2e295 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1670,10 +1670,21 @@ impl OpenCADStudio { Task::batch([open_main, check_update, focus_cmd, cli_open, assoc_prompt]), ) } + + /// Single-window boot for the web build: no OS-window creation (the browser + /// canvas is the only window), no file-association registration or CLI file + /// open. Secondary manager windows are unavailable on the web for now. + #[cfg(target_arch = "wasm32")] + fn boot_web() -> (Self, Task) { + let mut s = Self::new(); + let focus = s.focus_cmd_input(); + (s, focus) + } } use std::path::PathBuf; +#[cfg(not(target_arch = "wasm32"))] pub fn run() -> iced::Result { iced::daemon( OpenCADStudio::boot, @@ -1744,3 +1755,20 @@ pub fn run() -> iced::Result { .theme(|state: &OpenCADStudio, _| state.active_theme.clone()) .run() } + +/// Single-window entry for the web (wasm) build. Uses `iced::application` +/// instead of `iced::daemon`: the browser canvas is the only window, so the +/// main-window view is rendered directly and the manager/dialog windows are +/// unavailable for now (see issue #45). Native keeps the multi-window `run`. +#[cfg(target_arch = "wasm32")] +pub fn run_web() -> iced::Result { + iced::application( + OpenCADStudio::boot_web, + OpenCADStudio::update, + OpenCADStudio::view_main, + ) + .subscription(OpenCADStudio::subscription) + .title(|_state: &OpenCADStudio| "Open CAD Studio".to_string()) + .theme(|state: &OpenCADStudio| state.active_theme.clone()) + .run() +} diff --git a/src/app/view.rs b/src/app/view.rs index 75339340..44703435 100644 --- a/src/app/view.rs +++ b/src/app/view.rs @@ -511,6 +511,13 @@ impl OpenCADStudio { ); } + self.view_main() + } + + /// The primary window: viewport, ribbon, tab bar, status bar. Split out of + /// `view` so the single-window web build can render it directly, bypassing + /// the multi-window id dispatch above (the web build has no extra windows). + pub fn view_main(&self) -> Element<'_, Message> { let i = self.active_tab; let tab = &self.tabs[i]; let is_paper = tab.scene.current_layout != "Model"; diff --git a/src/main.rs b/src/main.rs index 0a3427e9..c7cff8cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,5 +28,16 @@ fn main() -> iced::Result { if std::env::var_os("WGPU_BACKEND").is_none() { std::env::set_var("WGPU_BACKEND", "dx12,vulkan"); } - app::run() + + // Web (wasm) uses the single-window entry; native uses the multi-window + // daemon. Trunk calls `main` from its generated JS bootstrap. + #[cfg(target_arch = "wasm32")] + { + console_error_panic_hook::set_once(); + app::run_web() + } + #[cfg(not(target_arch = "wasm32"))] + { + app::run() + } }