//! Browser entry point for the Ferrous Solitaire Bevy WASM build. //! //! This crate compiles the full `solitaire_engine` to `wasm32-unknown-unknown` //! and renders to a `` element. It shares the same //! ECS code path as the desktop and Android builds; the only differences are: //! - Audio, sync, and analytics plugins are cfg-gated out in `CoreGamePlugin` //! on the wasm32 target (see `solitaire_engine/src/core_game_plugin.rs`). //! - `LocalOnlyProvider` is passed as the sync provider (sync is disabled). //! - Storage is handled automatically by `WasmStorage` (localStorage-backed), //! wired by `CoreGamePlugin` via `default_storage_backend()`. use bevy::asset::AssetMetaCheck; use bevy::prelude::*; use bevy::render::RenderPlugin; use bevy::render::settings::{RenderCreation, WgpuSettings, WgpuSettingsPriority}; use bevy::window::{Window, WindowPlugin, WindowResolution}; use solitaire_data::LocalOnlyProvider; use solitaire_engine::CoreGamePlugin; use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn start() { console_error_panic_hook::set_once(); App::new() .add_plugins( DefaultPlugins .set(WindowPlugin { primary_window: Some(Window { // Bind to the existing in play.html. // Without this, Bevy appends its own canvas to . canvas: Some("#bevy-canvas".into()), // Let CSS size the canvas; Bevy follows the element's size. fit_canvas_to_parent: true, // Prevent the browser stealing keyboard events and scroll. prevent_default_event_handling: true, // Render at CSS/logical pixels (scale_factor 1.0) rather // than physical (CSS × devicePixelRatio). This keeps the // surface smaller on HiDPI displays — lighter GPU load and // stable sizing — at the cost of some crispness. The wgpu // texture-dimension limit is now taken from the adapter (see // the RenderPlugin below), so this is purely a quality/perf // choice, no longer a crash-avoidance hack. resolution: WindowResolution::default().with_scale_factor_override(1.0), ..default() }), ..default() }) // Bevy's default AssetPlugin fetches a `.meta` sidecar file for // every asset before loading the asset itself. We don't ship // `.meta` files, so skip the check to avoid a flood of 404s. .set(AssetPlugin { meta_check: AssetMetaCheck::Never, ..default() }) // `Functionality` makes wgpu adopt the *adapter's* real limits // instead of the conservative `downlevel_webgl2_defaults()` that // `WebGL2` priority forces. On the WebGL2 (Gl) backend the adapter // already reports WebGL2-constrained features/limits — no storage // buffers, etc., so shaders stay GLES-compatible on both Firefox and // Chromium — but it reports the GPU's *true* `max_texture_dimension` // (e.g. 16384) rather than 2048. The device is requested with exactly // what the adapter offers, so creation can't fail, and the surface is // no longer capped at 2048: large viewports (4K, etc.) render natively // with no letterbox and no hardcoded cap. .set(RenderPlugin { render_creation: RenderCreation::Automatic(WgpuSettings { priority: WgpuSettingsPriority::Functionality, ..default() }), ..default() }), ) // LocalOnlyProvider disables cloud sync — correct for the web build // since SyncPlugin is cfg-gated out on wasm32 anyway. .add_plugins(CoreGamePlugin::new(Box::new(LocalOnlyProvider))) .run(); }