Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| afb08799e8 | |||
| 3b619b8950 | |||
| 37681cf33e | |||
| 99064ce808 | |||
| de4dba6f98 | |||
| 75fc3aa3d6 | |||
| deb034c5fb | |||
| 242b5fef21 | |||
| 3f922ede28 | |||
| 8da62bd05f | |||
| 73cad7e205 | |||
| e14852c093 | |||
| 6240156fee | |||
| 1d9fb1884a | |||
| 97f38085e3 | |||
| 62cd1cf924 | |||
| b10e1a5a87 | |||
| 366fd6d127 | |||
| 7a77c66f6d | |||
| adece12cf1 | |||
| 2cfbc32715 | |||
| 56b37fc653 | |||
| 3ffde038c5 | |||
| ece2a55ffb | |||
| abda354562 | |||
| fbe984cf64 | |||
| efec6f22d5 |
@@ -51,6 +51,7 @@ Solitaire Quest is a cross-platform Klondike Solitaire game written in Rust, tar
|
||||
- **No panics in game logic.** Every state transition returns `Result<_, MoveError>`. Panics are only acceptable in startup/configuration code.
|
||||
- **One language, one repo.** The game client, sync client, shared types, and sync server are all Rust crates in a single Cargo workspace.
|
||||
- **Plugin-based Bevy architecture.** Each major feature is a Bevy `Plugin`. Systems are small and single-purpose. Cross-system communication uses Bevy `Event`s.
|
||||
- **UI-first interaction.** Every player-triggered action — new game, undo, draw, pause, open stats / settings / help / profile / leaderboard, etc. — must be reachable from a visible UI control. Keyboard shortcuts exist only as optional accelerators for power users; they are never the sole entry point. A player using only mouse or touch must be able to perform every action. New gameplay features ship with the UI control alongside the system that backs it.
|
||||
|
||||
---
|
||||
|
||||
@@ -67,11 +68,11 @@ solitaire_quest/
|
||||
├── Dockerfile # Multi-stage server build
|
||||
├── docker-compose.yml # Server + Caddy reverse proxy
|
||||
│
|
||||
├── assets/ # Assets embedded at compile time via include_bytes!()
|
||||
├── assets/ # Loaded at runtime via AssetServer (audio is embedded via include_bytes!())
|
||||
│ ├── cards/
|
||||
│ │ ├── faces/{rank}_{suit}.png # 52 individual card faces (120×168, generated by solitaire_assetgen)
|
||||
│ │ └── backs/back_0.png – back_4.png # placeholder patterns
|
||||
│ ├── backgrounds/bg_0.png – bg_4.png # placeholder textures
|
||||
│ │ ├── faces/{RANK}{SUIT}.png # 52 card faces — xCards @2x artwork (LGPL-3.0)
|
||||
│ │ └── backs/back_0.png – back_4.png # back_0 = xCards bicycle_blue; back_1–4 are generated patterns
|
||||
│ ├── backgrounds/bg_0.png – bg_4.png # generated textures
|
||||
│ ├── fonts/main.ttf # FiraMono-Medium (170K, OFL)
|
||||
│ └── audio/
|
||||
│ ├── card_deal.wav
|
||||
@@ -144,7 +145,7 @@ Owns:
|
||||
- All Bevy UI screens (Home, Stats, Achievements, Settings, Profile)
|
||||
- Audio playback systems
|
||||
- Sync status display
|
||||
- Card, background, and font asset loading (embedded via `include_bytes!()` — no `AssetServer` dependency)
|
||||
- Card, background, and font asset loading via Bevy `AssetServer` (audio is the lone exception — embedded via `include_bytes!()` in `audio_plugin.rs`)
|
||||
|
||||
### `solitaire_server`
|
||||
**Dependencies:** `solitaire_sync`, `axum`, `sqlx`, `jsonwebtoken`, `bcrypt`, `tower-governor`, `tracing`, `tokio`, `dotenvy`.
|
||||
@@ -235,11 +236,13 @@ Done
|
||||
|
||||
### Bevy Plugins
|
||||
|
||||
| Plugin | Key | Responsibility |
|
||||
The "Shortcut" column lists optional keyboard accelerators. Every action in this table must also be reachable from a visible UI control (button, menu item, on-screen affordance) per the UI-first design principle in §1; the shortcut is a power-user convenience, not the sole entry point.
|
||||
|
||||
| Plugin | Shortcut | Responsibility |
|
||||
|---|---|---|
|
||||
| `CardPlugin` | — | Card entity spawning, sprite management, drag-and-drop |
|
||||
| `TablePlugin` | — | Pile markers, background, layout calculation |
|
||||
| `FontPlugin` | — | Embeds FiraMono-Medium font at compile time; exposes `FontResource` handle |
|
||||
| `FontPlugin` | — | Loads FiraMono-Medium via `AssetServer` at startup; exposes `FontResource` handle |
|
||||
| `AnimationPlugin` | — | Slide, flip, win cascade, toast animations |
|
||||
| `FeedbackAnimPlugin` | — | Shake, settle, and deal-stagger animations |
|
||||
| `AutoCompletePlugin` | Enter | Executes auto-complete when the HUD badge is lit |
|
||||
@@ -248,7 +251,7 @@ Done
|
||||
| `CursorPlugin` | — | Custom cursor sprite during drag |
|
||||
| `SelectionPlugin` | — | Keyboard-driven card selection |
|
||||
| `GamePlugin` | N | Core game state resource, new-game flow, win/game-over overlays |
|
||||
| `HudPlugin` | — | Score, move counter, timer, auto-complete badge |
|
||||
| `HudPlugin` | — | Score, move counter, timer, auto-complete badge, and the top-right action button bar (Undo / Pause / Help / New Game). Each button fires the same request event the corresponding hotkey does. |
|
||||
| `StatsPlugin` | S | Stats overlay and persistence |
|
||||
| `ProgressPlugin` | — | XP/level system, persistence |
|
||||
| `AchievementPlugin` | A | Unlock evaluation, toast events, persistence |
|
||||
@@ -296,7 +299,7 @@ struct CardImageSet {
|
||||
backs: [Handle<Image>; 5], // indexed by selected_card_back setting
|
||||
}
|
||||
|
||||
// Project-wide font handle (FiraMono-Medium embedded at compile time)
|
||||
// Project-wide font handle (FiraMono-Medium loaded via AssetServer at startup)
|
||||
struct FontResource(Handle<Font>);
|
||||
|
||||
// Pre-loaded background PNG handles
|
||||
@@ -772,11 +775,13 @@ Audio systems listen for Bevy events and never block the game thread.
|
||||
|
||||
### Rendering approach
|
||||
|
||||
Cards are Bevy `Sprite` entities with `Handle<Image>` from `CardImageSet`. Face-up cards use one of 52 individual face PNGs selected by `faces[suit][rank]` — rank and suit are baked into each image and no `Text2d` overlay is spawned. Face-down cards use `backs/back_N.png` indexed by `settings.selected_card_back`. `Text2d` labels are only used as a fallback when `CardImageSet` is absent (e.g. tests with `MinimalPlugins`). `CardImageSet` is populated at startup from `include_bytes!()` — no `AssetServer`.
|
||||
Cards are Bevy `Sprite` entities with `Handle<Image>` from `CardImageSet`. Face-up cards use one of 52 individual face PNGs selected by `faces[suit][rank]` — rank and suit are baked into each image and no `Text2d` overlay is spawned. Face-down cards use `backs/back_N.png` indexed by `settings.selected_card_back`. `Text2d` labels are only used as a fallback when `CardImageSet` is absent (e.g. tests with `MinimalPlugins`). `CardImageSet` is populated at startup by `card_plugin::load_card_images` via `AssetServer::load()`.
|
||||
|
||||
Backgrounds are Bevy `Sprite` entities with `Handle<Image>` from `BackgroundImageSet`. `BackgroundImageSet` is populated at startup from `include_bytes!()`.
|
||||
Backgrounds are Bevy `Sprite` entities with `Handle<Image>` from `BackgroundImageSet`. `BackgroundImageSet` is populated at startup by `table_plugin::load_background_images` via `AssetServer::load()`.
|
||||
|
||||
The font `FiraMono-Medium` is embedded via `include_bytes!()` at startup by `FontPlugin` and exposed as `FontResource` for use by all UI and text systems.
|
||||
The font `FiraMono-Medium` is loaded via `AssetServer::load("fonts/main.ttf")` at startup by `FontPlugin` and exposed as `FontResource` for use by all UI and text systems.
|
||||
|
||||
All three loaders take `Option<Res<AssetServer>>` so they degrade cleanly under `MinimalPlugins` in tests: when the server is absent, `CardImageSet`/`BackgroundImageSet` are inserted with empty handle slots and the plugins fall back to `Text2d` rank+suit overlays and solid-colour board backgrounds. The `assets/` directory must ship alongside the binary.
|
||||
|
||||
The `assets/` directory layout:
|
||||
|
||||
@@ -1004,5 +1009,5 @@ Using `axum::test` and an in-memory SQLite database:
|
||||
| `SyncProvider` trait, not `SyncBackend` match arms | `SyncPlugin` stays backend-agnostic and testable; new backends can be added without touching the plugin | 2026-04-20 |
|
||||
| Dropped WebDAV backend | Redundant once the self-hosted server exists; removing it reduces surface area and simplifies settings UI | 2026-04-20 |
|
||||
| Dropped GPGS backend | Redundant with the self-hosted server; adds JNI complexity for no user-visible benefit on the target platforms | 2026-04-28 |
|
||||
| PNG assets embedded via `include_bytes!()` | Using `Image::from_buffer()` in startup systems rather than `AssetServer::load()` keeps the binary self-contained and eliminates runtime file-not-found errors | 2026-04-29 |
|
||||
| FiraMono-Medium font embedded via `include_bytes!()` | Exposed through `FontResource`; avoids runtime font loading errors on headless systems and ensures consistent text rendering across all platforms | 2026-04-29 |
|
||||
| Card, background, and font assets loaded via `AssetServer` | Reverses the earlier embed-via-`include_bytes!()` decision: PNGs and TTFs are loaded at runtime so artwork can be swapped (e.g. xCards @2x faces, alternate card backs, themed backgrounds) without a recompile, and binary size stays small. Loaders take `Option<Res<AssetServer>>` and fall back gracefully under `MinimalPlugins`. The `assets/` directory must ship alongside the binary. | 2026-04-29 |
|
||||
| Audio assets remain embedded via `include_bytes!()` | Audio files are small, change rarely, and the embedded path eliminates a class of runtime-load errors during gameplay; the asset-pipeline reversal does not extend to audio | 2026-04-29 |
|
||||
|
||||
@@ -47,7 +47,9 @@ 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>`.
|
||||
- Audio assets are embedded at compile time using `include_bytes!()` in `audio_plugin.rs`. Cards and backgrounds are rendered procedurally (colored `Sprite` entities + text) — no image files are used and no `AssetServer` is needed.
|
||||
- Audio assets are embedded at compile time using `include_bytes!()` in `audio_plugin.rs`.
|
||||
- Card faces (52 PNGs in `assets/cards/faces/`), card backs (`assets/cards/backs/back_N.png`), board backgrounds (`assets/backgrounds/bg_N.png`), and the UI font (`assets/fonts/main.ttf`) are loaded at runtime via `AssetServer::load()` and stored as `Handle<Image>`/`Handle<Font>` in the `CardImageSet`, `BackgroundImageSet`, and `FontResource` resources. The `assets/` directory must ship alongside the binary.
|
||||
- Asset-loading systems take `Option<Res<AssetServer>>` so they degrade cleanly under `MinimalPlugins` (tests). When `CardImageSet` is absent, `card_plugin` falls back to a `Text2d` rank+suit overlay; when `BackgroundImageSet` is absent, the board falls back to a solid colour.
|
||||
- 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,6 +77,7 @@ cargo clippy -p solitaire_core -- -D warnings
|
||||
- Resources own shared state. Events communicate between systems. Components own per-entity data.
|
||||
- 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.
|
||||
- **UI-first.** Every player-triggered action (new game, undo, draw, pause, open stats / settings / help / profile / leaderboard, switch mode, etc.) must be reachable from a visible UI control. Keyboard shortcuts are optional accelerators — never the sole entry point. New gameplay features ship with the UI control alongside the system that backs it; do not merge a feature that is keyboard-only.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# Solitaire Quest — UX Overhaul Session Handoff
|
||||
|
||||
**Last updated:** 2026-04-30 — paused mid-overhaul to push and let the user smoke-test before resuming.
|
||||
|
||||
## Where we are
|
||||
|
||||
Phase 3 of the UX overhaul brief in `docs/UX_OVERHAUL_BRIEF.md` (or the inline brief used to kick off the work). 11 commits landed this session — the foundation, the HUD, and every read-only overlay have been migrated to the new design system. Pause / Settings / Onboarding modals, animation upgrades, and the final literal sweep are still pending.
|
||||
|
||||
### Design direction (already saved as project memory)
|
||||
|
||||
- **Tone:** Balatro — chunky readable type, theatrical hierarchy, satisfying micro-interactions.
|
||||
- **Palette:** Midnight Purple base (`BG_BASE` `#1A0F2E` → `BG_ELEVATED` `#2D1B69` → `BG_ELEVATED_HI` `#3A2580` → `BG_ELEVATED_TOP` `#482F97`) + Balatro yellow primary accent (`ACCENT_PRIMARY` `#FFD23F`) + warm magenta secondary (`ACCENT_SECONDARY` `#FF6B9D`).
|
||||
- See [memory/project_ux_overhaul_2026-04.md](.claude/projects/-home-manage-Rusty-Solitare/memory/project_ux_overhaul_2026-04.md) for the full direction.
|
||||
|
||||
### Top complaints from the original smoke test
|
||||
|
||||
1. **HUD too cluttered.** ✅ Closed by `73cad7e` — readouts now sit in a 4-tier vertical stack with progressive disclosure of penalty/bonus tiers.
|
||||
2. **Y/N keyboard prompts feel like debug panels.** ✅ Closed for the Confirm + GameOver modals (`3f922ed`, `242b5fe`); still open for the Forfeit toast countdown (folded into step 6 below).
|
||||
|
||||
## Foundation (done)
|
||||
|
||||
- **`solitaire_engine/src/ui_theme.rs`** — every design token: colours, 5-rung typography scale, 4-multiple spacing scale, three radius rungs, monotonically-ordered z-index hierarchy, motion durations with `scaled_duration(speed)` helper.
|
||||
- **`solitaire_engine/src/ui_modal.rs`** — `spawn_modal` scaffold + `spawn_modal_header` / `spawn_modal_body_text` / `spawn_modal_actions` / `spawn_modal_button` helpers + `ButtonVariant` enum (Primary / Secondary / Tertiary) + `paint_modal_buttons` system. `UiModalPlugin` registered in `solitaire_app/src/main.rs`.
|
||||
|
||||
Every overlay conversion follows the same pattern: drop the bespoke scrim/card, call `spawn_modal(MarkerComponent, Z_MODAL_PANEL, |card| { ... })`, swap inline colours for tokens, replace "Press X to close" prose with a primary `Done` button + matching click-handler system.
|
||||
|
||||
## Commits this session
|
||||
|
||||
```
|
||||
3b619b8 feat(engine): convert HomeScreen to modal scaffold + Done button
|
||||
37681cf feat(engine): convert LeaderboardScreen to modal scaffold + Done button
|
||||
99064ce feat(engine): convert ProfileScreen to modal scaffold + Done button
|
||||
de4dba6 feat(engine): convert AchievementsScreen to modal scaffold + Done button
|
||||
75fc3aa feat(engine): convert StatsScreen to modal scaffold + Done button
|
||||
deb034c feat(engine): convert HelpScreen to real-button modal with kbd-chip rows
|
||||
242b5fe feat(engine): convert GameOverScreen to real-button modal
|
||||
3f922ed feat(engine): convert ConfirmNewGameScreen to real-button modal
|
||||
8da62bd feat(engine): add ui_modal primitive (scaffold + button variants)
|
||||
73cad7e feat(engine): restructure HUD into 4-tier layout, adopt design tokens
|
||||
e14852c feat(engine): add ui_theme.rs design-token module
|
||||
```
|
||||
|
||||
**Test status across every commit:** `cargo build --workspace` clean, `cargo clippy --workspace -- -D warnings` clean, **797 tests pass / 0 failed / 8 ignored**.
|
||||
|
||||
## What's still on disk in pre-overhaul style
|
||||
|
||||
| Step | Area | What it'll touch |
|
||||
|---|---|---|
|
||||
| 6 | Pause overlay + Forfeit modal | `pause_plugin.rs` (replace bespoke spawn with modal scaffold); fold Forfeit toast countdown into a real Cancel/Forfeit modal — Forfeit then becomes a button inside Pause. Tests around `forfeit_countdown` will need updating. |
|
||||
| 7 | Settings panel | `settings_plugin.rs` — replaces the side-panel pattern with the modal scaffold. Sections: Audio / Gameplay / Cosmetic / Sync. The existing per-button click handlers stay; only the spawn structure and styling change. |
|
||||
| 8 | Onboarding | `onboarding_plugin.rs` — multi-slide flow (Welcome → Drag-drop demo → Hotkeys), navigated by a primary `Next` button + arrow-key accelerators. Final slide `Start playing` writes `first_run_complete` like today. |
|
||||
| 9 | Animation upgrades | `animation_plugin.rs`, `feedback_anim_plugin.rs`, `card_animation/`, `win_summary_plugin.rs` — promote `card_animation::MotionCurve` to default for slide; settle bounce only on the moved card; deal stagger ±10% jitter; win cascade with `Expressive` curve + per-card rotation; align all durations through `ui_theme::scaled_duration`. |
|
||||
| 10 | Literal-to-token sweep | Grep the engine for any remaining `Color::srgb`/`Val::Px(<literal>)`/font-size literal and migrate. Clippy gates this — anything left over surfaces during the build. |
|
||||
|
||||
ETA for the rest: roughly 5–7 more focused commits, each independently passing `build` / `clippy` / `test`.
|
||||
|
||||
## Smoke-test checklist before resuming
|
||||
|
||||
The user smoke-tested at the action-bar checkpoint and reported "nothing looks off". Worth re-running once these 11 commits are pushed so the next session starts from a verified baseline:
|
||||
|
||||
- HUD layout reads as 4 stacked tiers (Score / Mode / Penalty / Selection) with the new midnight-purple palette.
|
||||
- Open every overlay (S, A, P, O, L, M, F1) — each should now be a centred card on a uniform scrim, with a `Done` primary button.
|
||||
- Click `New Game` while a game is in progress — the abandon-current-game modal should be a real-button card; both `Y/Enter` and the yellow primary button start a new game; both `N/Esc` and the secondary button cancel.
|
||||
- Force a stuck state — the Game Over modal should show real Undo / New Game buttons.
|
||||
- Resize the window — cards still snap, no "snap-back-and-forth" jitter (covered by previous fixes `366fd6d` / `b10e1a5`).
|
||||
- Press G to forfeit — still uses the toast countdown (step 6 will replace this with a modal).
|
||||
|
||||
## Kickoff prompt for the next session
|
||||
|
||||
Paste this at the start of a fresh chat to resume:
|
||||
|
||||
```
|
||||
Resume the UX overhaul of Solitaire Quest at /home/manage/Rusty_Solitare/.
|
||||
|
||||
Read these in order before doing anything:
|
||||
1. SESSION_HANDOFF.md (this file)
|
||||
2. CLAUDE.md (project conventions; UI-first principle)
|
||||
3. The "Design direction" section of
|
||||
~/.claude/projects/-home-manage-Rusty-Solitare/memory/project_ux_overhaul_2026-04.md
|
||||
|
||||
The foundation (ui_theme.rs, ui_modal.rs), the HUD restructure, and
|
||||
all 8 read-only overlay conversions are committed. Steps 6 → 10 are
|
||||
documented in SESSION_HANDOFF.md and listed in
|
||||
.claude/projects/.../memory/MEMORY.md.
|
||||
|
||||
Pick up at step 6 (Pause modal + folded-in Forfeit modal). Same
|
||||
shape as the existing modal conversions: spawn_modal scaffold, real
|
||||
buttons, hotkey-hint chips, ui_theme tokens for every colour /
|
||||
spacing / typography decision. Update or replace any test that
|
||||
asserted the prior bespoke layout.
|
||||
|
||||
Each commit must pass `cargo build --workspace`,
|
||||
`cargo clippy --workspace -- -D warnings`, and `cargo test --workspace`
|
||||
clean. Use commits authored by funman300 <root@vscode.infinity> via
|
||||
the -c flag (per the user's convention; never write to git config).
|
||||
|
||||
Stop after step 6 and ask the user to smoke-test before continuing to
|
||||
step 7. They prefer pause-and-verify over running through the
|
||||
remaining 4 steps in one push.
|
||||
```
|
||||
|
||||
## Open question
|
||||
|
||||
When the next session resumes, ask whether the user wants to:
|
||||
|
||||
1. **Keep Home as a kbd-reference modal** (current state — duplicates Help).
|
||||
2. **Convert Home into a true mode launcher** (Classic / Daily / Zen / Challenge / Time Attack cards, locked options visibly disabled below level 5) per the original Phase 2 proposal. The action-bar `Modes` popover already covers this path; pivoting Home buys discoverability for first-time players who hit `M`.
|
||||
3. **Drop Home entirely.** With the action bar covering every action and Help covering every shortcut, Home may be redundant.
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 2.3 MiB |
|
After Width: | Height: | Size: 212 KiB |
|
After Width: | Height: | Size: 147 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 161 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 162 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 145 KiB |
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 210 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 166 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.0 KiB |