chore(deps): replace bevy_egui+bevy_kira_audio with bevy_ui+kira, drop AssetServer

This commit is contained in:
Solitaire Quest
2026-04-23 21:02:46 -07:00
parent b3646d6cad
commit a8a323c6c3
7 changed files with 450 additions and 1823 deletions
+4 -4
View File
@@ -6,7 +6,7 @@ See @ARCHITECTURE.md for full project design, crate responsibilities, data model
## Project Layout
```
```text
solitaire_core/ # Pure Rust game logic — NO Bevy, NO network, NO I/O
solitaire_sync/ # Shared API types — NO Bevy, serde/uuid/chrono only
solitaire_data/ # Persistence + SyncProvider trait + server client
@@ -14,7 +14,7 @@ solitaire_engine/ # Bevy ECS systems, components, plugins
solitaire_server/ # Axum sync server binary
solitaire_gpgs/ # Google Play Games bridge — STUB ONLY until Android phase
solitaire_app/ # Thin binary entry point
assets/ # Loaded at runtime via Bevy AssetServer only
assets/ # Source assets — embedded at compile time via include_bytes!()
```
---
@@ -48,7 +48,7 @@ cargo clippy -p solitaire_core -- -D warnings
- `solitaire_core` and `solitaire_sync` must never gain Bevy or network dependencies.
- No `unwrap()` or `panic!()` in game logic. All state transitions return `Result<_, MoveError>`.
- No hardcoded bytes in source. All assets go through Bevy's `AssetServer`.
- Assets are embedded at compile time using `include_bytes!()`. No runtime asset loading via `AssetServer`.
- Atomic file writes only: write to `filename.json.tmp`, then `rename()`.
- Passwords and tokens are stored in the OS keychain via the `keyring` crate — never in plaintext files or logs.
- Sync runs on `AsyncComputeTaskPool` — never block the Bevy main thread.
@@ -75,7 +75,7 @@ cargo clippy -p solitaire_core -- -D warnings
- One `Plugin` per major feature: `CardPlugin`, `AudioPlugin`, `AchievementPlugin`, `UIPlugin`, `SyncPlugin`.
- Resources own shared state. Events communicate between systems. Components own per-entity data.
- All egui screens live in `solitaire_engine::ui`. Never mix egui and Bevy spawn logic in the same system.
- All UI screens are built with Bevy UI (`bevy::ui`). Never mix UI layout and game logic in the same system.
- Layout is recomputed on `WindowResized` — never assume a fixed window size.
---
Generated
+423 -1803
View File
File diff suppressed because it is too large Load Diff
+2 -3
View File
@@ -32,9 +32,8 @@ solitaire_sync = { path = "solitaire_sync" }
solitaire_data = { path = "solitaire_data" }
solitaire_engine = { path = "solitaire_engine" }
bevy = "0.15"
bevy_egui = "0.30"
bevy_kira_audio = "0.21"
bevy = "0.15"
kira = "0.9"
axum = "0.7"
sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] }
+10 -3
View File
@@ -106,11 +106,18 @@ See the full spec in the master prompt (originally pasted by the user) or in `AR
## Important Implementation Notes
### Versions (Cargo.toml workspace deps)
- `bevy = "0.15"` (resolved to 0.15.3)
- `bevy_egui = "0.30"` (0.30.1)
- `bevy_kira_audio = "0.21"` (0.21.0)
- `bevy = "0.15"` (resolved to 0.15.3) — UI via built-in `bevy::ui`, no bevy_egui
- `kira = "0.9"` — audio via `kira` crate directly, no bevy_kira_audio or AssetServer
- `rand = "0.8"` — note: `small_rng` feature is NOT enabled; use `StdRng`, not `SmallRng`
### Asset strategy
- No `AssetServer` — assets embedded at compile time using `include_bytes!()`
- Fonts: `Font::try_from_bytes(include_bytes!("../assets/fonts/main.ttf"))`
- Audio: load from `&[u8]` via `kira` `StaticSoundData::from_cursor()`
- Card rendering: procedural (`bevy::prelude::Sprite` + `Text2d`) — no sprite sheets required
### Hard rules (from CLAUDE.md)
- `solitaire_core` and `solitaire_sync` must NEVER gain Bevy or network dependencies
- No `unwrap()` or `panic!()` in game logic — use `Result<_, MoveError>` everywhere
@@ -2,7 +2,7 @@
> Status: In progress (started 2026-04-23)
> Crate: `solitaire_engine`
> Depends on: `solitaire_core` (complete), `bevy = 0.15`, `bevy_egui = 0.30`
> Depends on: `solitaire_core` (complete), `bevy = 0.15` (includes `bevy::ui`), `kira = 0.9` (audio — Phase 3F+)
---
@@ -11,6 +11,7 @@
Make the game playable with a graphical interface. This phase takes `solitaire_engine` from an empty stub to a full Bevy rendering + input layer wired to `solitaire_core::GameState`.
Out of scope (later phases):
- Persistence (`StatsSnapshot`, file I/O) — Phase 4
- Achievements toast content — Phase 5
- Audio — Phase 7
@@ -136,7 +137,7 @@ Commit: `feat(engine): add drag-and-drop input with multi-card tableau support`
- Component `CardAnim { start: Vec3, target: Vec3, elapsed: f32, duration: f32 }` — linear lerp 0.15s for moves
- Flip: `CardFlip { elapsed: f32, duration: f32, flips_to_face_up: bool }` — scale-X 1→0→1 over 0.2s, toggle `face_up` at midpoint, fire `CardFlippedEvent`
- Win cascade: on `GameWonEvent`, iterate foundation cards and schedule `CardAnim` to random off-screen targets with staggered 0.05s starts
- Toast component scaffold: egui popup placeholder, wired to `AchievementUnlockedEvent` (no content yet)
- Toast component scaffold: bevy_ui `Node`/`Text` overlay, wired to `AchievementUnlockedEvent` (no content yet)
**Exit:** Valid moves animate smoothly; flipping a tableau card shows a flip; winning plays a cascade.
@@ -167,5 +168,5 @@ Commit: `feat(engine): add AnimationPlugin with slide, flip, and win cascade`
## Risks
- Bevy 0.15 API drift from older tutorials — verify each API call as written.
- `bevy_egui` 0.30 may require slightly different system ordering than earlier versions — pin to workspace versions, don't downgrade.
- Procedural card text depends on Bevy's default font; if rendering is unreadable, drop in a `.ttf` to `assets/fonts/main.ttf` as a follow-up (still Phase 3, not 3F).
- Procedural card text depends on Bevy's default font; if rendering is unreadable, embed a `.ttf` via `include_bytes!()` as a follow-up (still Phase 3, not 3F).
- `kira` audio API is async-friendly but requires careful thread management — initialise the `AudioManager` once at startup and store it in a Bevy `NonSend` resource.
+5 -6
View File
@@ -4,9 +4,8 @@ version.workspace = true
edition.workspace = true
[dependencies]
bevy = { workspace = true }
bevy_egui = { workspace = true }
bevy_kira_audio = { workspace = true }
solitaire_core = { workspace = true }
solitaire_data = { workspace = true }
chrono = { workspace = true }
bevy = { workspace = true }
kira = { workspace = true }
solitaire_core = { workspace = true }
solitaire_data = { workspace = true }
chrono = { workspace = true }
+1
View File
@@ -187,6 +187,7 @@ fn follow_drag(
}
}
#[allow(clippy::too_many_arguments)]
fn end_drag(
buttons: Res<ButtonInput<MouseButton>>,
windows: Query<&Window, With<PrimaryWindow>>,