191 lines
9.3 KiB
Markdown
191 lines
9.3 KiB
Markdown
## Title
|
|
|
|
Packaged `sprimo-tauri` sprite rendering breaks after pack switch; default switch errors and
|
|
scaling stops applying.
|
|
|
|
## Severity
|
|
|
|
P1
|
|
|
|
## Environment
|
|
|
|
- OS: Windows
|
|
- App version/build: packaged release (`sprimo-tauri.exe`)
|
|
- Renderer/backend details: Tauri main overlay + settings pop-out
|
|
- Evidence screenshots:
|
|
- `issues/screenshots/issue4.png`
|
|
- `issues/screenshots/issue4-b.png`
|
|
- `issues/screenshots/issue4-c.png`
|
|
- `issues/screenshots/issue4-after-fix2-2026-02-14-145819.png`
|
|
- `issues/screenshots/issue4-after-fix4-2026-02-14-153233.png`
|
|
|
|
## Summary
|
|
|
|
In packaged runtime, sprite display is incorrectly split/tiled, switching to `default` can fail,
|
|
and scaling becomes ineffective after the error.
|
|
|
|
## Reproduction Steps
|
|
|
|
1. Run packaged `sprimo-tauri.exe` from ZIP extract.
|
|
2. Open settings window.
|
|
3. Switch character between `ferris` and `default`.
|
|
4. Observe main overlay rendering and debug output.
|
|
5. Change scale slider.
|
|
|
|
## Expected Result
|
|
|
|
- Sprite sheet is split into the correct frame grid regardless of image resolution.
|
|
- Pack switching works for both `ferris` and `default`.
|
|
- Scale changes continue to apply after pack changes.
|
|
|
|
## Actual Result
|
|
|
|
- Main overlay shows incorrectly split/tiled sprite sheet.
|
|
- Pack switch can produce runtime error and break subsequent behavior.
|
|
- Scale update stops working reliably after the error.
|
|
|
|
## Root Cause Analysis
|
|
|
|
1. Existing splitting logic relied on fixed pixel frame metadata that did not generalize to
|
|
packaged `sprite.png` dimension variants.
|
|
2. Pack metadata inconsistency:
|
|
- `assets/sprite-packs/ferris/manifest.json` used duplicated `id` (`default`), causing pack
|
|
identity ambiguity.
|
|
3. Settings/runtime flow then entered an unstable state after pack switch failures.
|
|
4. Renderer reload lifecycle in tauri UI was unsafe:
|
|
- `PixiPetRenderer::dispose` performed duplicate teardown (`ticker.destroy` + `app.destroy`),
|
|
which could trigger runtime `TypeError` during pack reload.
|
|
- Renderer replacement disposed previous renderer before new renderer creation succeeded, leaving
|
|
the view in a broken/cropped state on creation failures.
|
|
5. Chroma-key conversion tolerance removed most `#FF00FF` background but still left magenta fringe
|
|
on anti-aliased edges.
|
|
6. Scale fit used repeated position deltas and caused directional drift during repeated resizing.
|
|
7. API mismatch in tauri window module:
|
|
- runtime used `getCurrentWindow().currentMonitor()` but this API version exposes monitor lookup as
|
|
module function (`currentMonitor`), causing `TypeError` and skipping window fit.
|
|
8. Scale position math mixed physical window metrics (`outerPosition`/`innerSize`) with logical
|
|
set operations (`LogicalSize`/`LogicalPosition`), reintroducing cumulative drift in some DPI
|
|
contexts.
|
|
9. Ferris background keying needed adaptive key detection; fixed `#FF00FF` assumptions were still
|
|
too brittle for packaged atlas variants.
|
|
10. Scale-path physical positioning used non-integer coordinates in `setPosition`, triggering
|
|
runtime arg errors (`expected i32`) and bypassing window fit updates.
|
|
11. Monitor-fit cap remained too optimistic for large frame packs, so max scale could still exceed
|
|
practical visible bounds and appear clipped.
|
|
12. Ferris/demogorgon packaged backgrounds are gradient-magenta (not exact `#FF00FF`), requiring a
|
|
border-connected magenta-family mask instead of exact-key assumptions.
|
|
|
|
## Fix Plan
|
|
|
|
1. Introduce generic splitter policy for `sprite.png`:
|
|
- fixed topology: `8` columns x `7` rows
|
|
- derive frame size from actual image dimensions
|
|
- keep chroma-key background handling (`#FF00FF`) in renderer
|
|
2. Validate animation frame indices against fixed frame count (`56`) for `sprite.png`.
|
|
3. Ensure pack apply path validates atlas geometry before committing `SetSpritePack`.
|
|
4. Fix ferris manifest ID uniqueness.
|
|
|
|
## Implementation Notes
|
|
|
|
Implemented:
|
|
|
|
1. `crates/sprimo-tauri/src/main.rs`
|
|
- Added `sprite.png`-specific frame derivation (`8x7`) from PNG dimensions.
|
|
- Added PNG header dimension decoding utility.
|
|
- Added animation frame index validation against fixed `56` frames for `sprite.png`.
|
|
- Applied validation in both `load_active_sprite_pack` and `set_sprite_pack`.
|
|
|
|
2. `assets/sprite-packs/ferris/manifest.json`
|
|
- Changed manifest `id` from `default` to `ferris`.
|
|
|
|
3. `docs/SPRITE_PACK_SCHEMA.md`
|
|
- Documented Tauri `sprite.png` override behavior and 8x7 derived frame policy.
|
|
|
|
4. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- Made renderer disposal idempotent and removed duplicate ticker destruction.
|
|
- Delayed DOM canvas replacement until atlas load succeeds.
|
|
- Improved chroma-key edge handling with soft alpha + magenta spill suppression.
|
|
|
|
5. `frontend/tauri-ui/src/main.tsx`
|
|
- Made pack reload transactional (keep old renderer until new renderer creation succeeds).
|
|
- Improved fit-window flow so scale apply continues after reload retries.
|
|
- Added targeted diagnostics for reload failures.
|
|
6. `frontend/tauri-ui/src/main.tsx`
|
|
- Changed scaling anchor to window center and clamped resized window position within current
|
|
monitor bounds.
|
|
7. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- Replaced tolerance-only chroma key with border-connected `#FF00FF` background flood-fill removal
|
|
and localized edge halo suppression.
|
|
8. `crates/sprimo-tauri/capabilities/default.json`
|
|
- Added `core:window:allow-current-monitor` permission for monitor bounds clamping.
|
|
9. `frontend/tauri-ui/src/main.tsx`
|
|
- switched monitor lookup to module-level `currentMonitor()` with safe fallback so window scaling
|
|
still applies even if monitor introspection is unavailable.
|
|
10. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- added fallback global key cleanup when border-connected background detection is too sparse.
|
|
11. `frontend/tauri-ui/src/main.tsx`
|
|
- moved scale resizing and positioning to physical units (`PhysicalSize`/`PhysicalPosition`) and
|
|
monitor selection at window-center point (`monitorFromPoint`).
|
|
12. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- added adaptive border-derived key color selection with fallback key cleanup pass.
|
|
13. `scripts/package_windows.py`
|
|
- tauri packaging now explicitly rebuilds UI bundle to avoid stale embedded `dist` output.
|
|
14. `frontend/tauri-ui/src/main.tsx`
|
|
- enforced integer physical positioning and monitor work-area size clamping to prevent set-position
|
|
arg failures and large-scale clipping.
|
|
15. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- switched ferris cleanup to hue/saturation/value magenta-band masking with connected background
|
|
removal and stronger fallback cleanup.
|
|
16. `frontend/tauri-ui/src/main.tsx`
|
|
- added stricter monitor work-area guard (`WINDOW_WORKAREA_MARGIN`) in both scale-cap and resize
|
|
clamp paths to prevent large-pack clipping at high scales.
|
|
17. `frontend/tauri-ui/src/renderer/pixi_pet.ts`
|
|
- added deterministic border-connected strong-magenta flood-fill cleanup pass so non-`#FF00FF`
|
|
gradient backgrounds are removed consistently in packaged ferris/demogorgon atlases.
|
|
|
|
## Verification
|
|
|
|
### Commands Run
|
|
|
|
- [ ] `just build-release-tauri`
|
|
- [ ] `just package-win-tauri`
|
|
- [ ] `just smoke-win-tauri`
|
|
- [x] `cargo check -p sprimo-tauri`
|
|
|
|
### Visual Checklist
|
|
|
|
- [x] Before screenshot(s): `issues/screenshots/issue4.png`
|
|
- [x] Before screenshot(s): `issues/screenshots/issue4-b.png`
|
|
- [x] Before screenshot(s): `issues/screenshots/issue4-c.png`
|
|
- [ ] After screenshot(s): `issues/screenshots/issue4-after-YYYYMMDD-HHMMSS.png`
|
|
|
|
### Result
|
|
|
|
- Status: `Fix Implemented`
|
|
- Notes: packaged runtime validation and after screenshots for this round are pending.
|
|
|
|
## Status History
|
|
|
|
- `2026-02-14 00:00` - reporter - `Reported` - packaged runtime failure screenshots attached.
|
|
- `2026-02-14 00:00` - codex - `Triaged` - localized to sprite splitting/pack identity behavior.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - applied 8x7 generic splitter policy and pack-ID correction.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - reported `issue4-after-fix1` still failing in packaged runtime.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - hardened renderer reload/dispose and chroma-key edge cleanup.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - remaining magenta ferris edge + scale drift reported.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - switched to border-connected chroma-key removal and center-anchored, monitor-clamped scale fit.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - reported `currentMonitor` TypeError and ferris magenta background still visible.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - corrected monitor API call and added fallback chroma cleanup pass.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - reported ferris magenta background still visible and scale drift recurrence.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - switched to physical-unit resize math, adaptive key detection, and packaging UI refresh enforcement.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - reported default clipping, ferris background still present, and set_position float arg error.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - added integer-safe physical setPosition and HSV magenta cleanup strategy.
|
|
- `2026-02-14 00:00` - reporter - `In Progress` - reported remaining default clipping and ferris magenta background persistence.
|
|
- `2026-02-14 00:00` - codex - `Fix Implemented` - tightened work-area scale guard and added border-connected strong-magenta cleanup pass.
|
|
|
|
## Closure
|
|
|
|
- Current Status: `Fix Implemented`
|
|
- Close Date:
|
|
- Owner:
|
|
- Linked PR/commit:
|