Files
Sprimo/issues/issue4.md
2026-02-14 17:08:29 +08:00

8.3 KiB

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.
  1. Settings/runtime flow then entered an unstable state after pack switch failures.
  2. 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.
  1. Chroma-key conversion tolerance removed most #FF00FF background but still left magenta fringe on anti-aliased edges.
  2. Scale fit used repeated position deltas and caused directional drift during repeated resizing.
  3. 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.
  1. Scale position math mixed physical window metrics (outerPosition/innerSize) with logical set operations (LogicalSize/LogicalPosition), reintroducing cumulative drift in some DPI contexts.
  2. Ferris background keying needed adaptive key detection; fixed #FF00FF assumptions were still too brittle for packaged atlas variants.
  3. Scale-path physical positioning used non-integer coordinates in setPosition, triggering runtime arg errors (expected i32) and bypassing window fit updates.

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
  1. Validate animation frame indices against fixed frame count (56) for sprite.png.
  2. Ensure pack apply path validates atlas geometry before committing SetSpritePack.
  3. 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.
  1. assets/sprite-packs/ferris/manifest.json
  • Changed manifest id from default to ferris.
  1. docs/SPRITE_PACK_SCHEMA.md
  • Documented Tauri sprite.png override behavior and 8x7 derived frame policy.
  1. 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.
  1. 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.
  1. frontend/tauri-ui/src/main.tsx
  • Changed scaling anchor to window center and clamped resized window position within current monitor bounds.
  1. 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.
  1. crates/sprimo-tauri/capabilities/default.json
  • Added core:window:allow-current-monitor permission for monitor bounds clamping.
  1. 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.
  1. frontend/tauri-ui/src/renderer/pixi_pet.ts
  • added fallback global key cleanup when border-connected background detection is too sparse.
  1. frontend/tauri-ui/src/main.tsx
  • moved scale resizing and positioning to physical units (PhysicalSize/PhysicalPosition) and monitor selection at window-center point (monitorFromPoint).
  1. frontend/tauri-ui/src/renderer/pixi_pet.ts
  • added adaptive border-derived key color selection with fallback key cleanup pass.
  1. scripts/package_windows.py
  • tauri packaging now explicitly rebuilds UI bundle to avoid stale embedded dist output.
  1. 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.
  1. 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.

Verification

Commands Run

  • just build-release-tauri
  • just package-win-tauri
  • just smoke-win-tauri
  • cargo check -p sprimo-tauri

Visual Checklist

  • Before screenshot(s): issues/screenshots/issue4.png
  • Before screenshot(s): issues/screenshots/issue4-b.png
  • 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.

Closure

  • Current Status: Fix Implemented
  • Close Date:
  • Owner:
  • Linked PR/commit: