// Adapted from CADCraft 0.12.0, Copyright (c) 2026 ArtCraft Team and contributors. // MIT OR Apache-2.0; see the adjacent upstream licences and NOTICE. // Bivar host: no browser persistence or native file picker; shared project controls own I/O. #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)] #[cfg(target_arch = "wasm32")] mod host; #[cfg(target_arch = "wasm32")] mod web { use cadcraft_engine::Session; use cadcraft_ui_egui::{CadApp, Services}; use wasm_bindgen::JsCast as _; struct Shell { app: CadApp, bridge: crate::host::Bridge, reported: Option, compact: bool, wide_panels: (bool, bool, bool), } impl eframe::App for Shell { fn logic(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { self.bridge.apply(&mut self.app); self.app.logic(ctx); } fn raw_input_hook(&mut self, ctx: &egui::Context, raw: &mut egui::RawInput) { self.app.raw_input_hook(raw); cadcraft_ui_egui::cmdline::capture_tab(ctx, raw); } fn persist_egui_memory(&self) -> bool { false } fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { let compact = ui.max_rect().width() < 760.0; if compact != self.compact { if compact { self.wide_panels = (self.app.ui.show_toolsets, self.app.ui.show_palettes, self.app.ui.show_viewcube); self.app.ui.show_toolsets = false; self.app.ui.show_palettes = false; self.app.ui.show_viewcube = false; } else { (self.app.ui.show_toolsets, self.app.ui.show_palettes, self.app.ui.show_viewcube) = self.wide_panels; } self.compact = compact; } self.app.ui(ui); self.bridge.report(&self.app, &mut self.reported); } } pub fn start() { eframe::WebLogger::init(log::LevelFilter::Warn).ok(); cadcraft_fonts::ttf::register("Bivar Noto Sans", include_bytes!("../bivar-font.ttf").to_vec()); cadcraft_fonts::ttf::set_fallback_fonts("Bivar Noto Sans"); cadcraft_engine::cmd::file::set_io(cadcraft_engine::cmd::file::IoHooks { read: |b, name| cadcraft_io::read(b, name).map_err(|e| e.to_string()), write: |d, name| cadcraft_io::write(d, name).map_err(|e| e.to_string()), plot: Some(|d, space, opts| cadcraft_io::plotter::plot(d, space, opts).map_err(|e| e.to_string())), }); cadcraft_engine::cmd::file::set_write_as(|d, name, o| { cadcraft_io::write_with(d, name, &cadcraft_io::SaveOptions { version: o.version, binary: o.binary }).map_err(|e| e.to_string()) }); cadcraft_engine::cmd::file::set_entity_codec(cadcraft_engine::cmd::file::EntityCodec { groups: cadcraft_io::entity_groups, entity: cadcraft_io::entity_from_groups, }); cadcraft_engine::cmd::file::set_deliver(crate::host::deliver); wasm_bindgen_futures::spawn_local(async move { let Some(window) = web_sys::window() else { return }; let Some(document) = window.document() else { return }; let Some(canvas) = document.get_element_by_id("cadcraft_canvas").and_then(|e| e.dyn_into::().ok()) else { return }; let origin = window.location().origin().unwrap_or_default(); let mut options = eframe::WebOptions::default(); if let eframe::egui_wgpu::WgpuSetup::CreateNew(create) = &mut options.wgpu_options.wgpu_setup { create.instance_descriptor.backends = eframe::wgpu::Backends::GL; } let result = eframe::WebRunner::new().start(canvas, options, Box::new(move |cc| { cc.egui_ctx.set_zoom_factor(1.1); let bridge = crate::host::Bridge::new(cc.egui_ctx.clone()); bridge.install(); let picker = bridge.clone(); let exporter = bridge.clone(); let services = Services { pick_open: Some(Box::new(move || { picker.pick(); None })), pick_save: Some(Box::new(|name: &str| Some(name.to_owned()))), export_drawing: Some(Box::new(move |name: &str| exporter.export_drawing(name))), }; let mut app = CadApp::new(Session::empty(), services); app.system_languages = vec!["en".into()]; app.system_animations = Some(false); if let Some(rs) = &cc.wgpu_render_state { app.set_wgpu(rs, None); } bridge.ready(); Ok(Box::new(Shell { app, bridge, reported: None, compact: false, wide_panels: (true, true, true) })) })).await; if let Err(error) = result { crate::host::startup_failed(&window, &origin, &format!("The drawing engine could not start: {error:?}")); } }); } } #[cfg(target_arch = "wasm32")] fn main() { web::start(); } #[cfg(not(target_arch = "wasm32"))] fn main() { eprintln!("Build cadcraft-web for wasm32-unknown-unknown"); }