Porting a complex React app like Scratch-GUI to mobile using Capacitor can surface bugs that don't appear on desktop. Recently, we fixed a frustrating issue: backdrop edits (drawings and erasures) weren't saving in .sb3 files on Android.
Here's what went wrong and how we fixed it.
1. The Main Problem: Edits Weren't Saving
Two issues caused backdrop changes to disappear when saving.
A. Storage Configuration Typo
In storage.js, we had a typo in the asset storage config. It was trying to use invalid "create" and "update" helpers, triggering failed network requests in the Capacitor environment.
Fix: Corrected the typo and simplified addWebStore to only use the GET helper for local assets.
B. Save Button Didn't Commit Pending Edits
The Paint Editor (from scratch-paint) normally saves changes when you click away from the canvas. On Android, clicking the "Save" button didn't trigger that "focus lost" event, so the latest drawing wasn't being saved.
Fix: Added a manual sync step before saving — calling document.activeElement.blur() and waiting 100ms to ensure all edits were committed.
2. The reader.addEventListener Error
We hit a strange error: TypeError: reader.addEventListener is not a function — and it only appeared on Android.
It turns out that in some environments, FileReader doesn't fully support addEventListener. It only has onload and onerror callbacks.
Fix: Added a lightweight polyfill at app startup that adds addEventListener support to FileReader.prototype, mapping it to the existing handler properties.
3. Canvas Performance Warning
Android's WebView kept showing this warning:
Canvas2D: Multiple readback operations using getImageData are faster with the willReadFrequently attribute set to true.
This happens when the canvas is read often — like in Scratch's "touching color" blocks and paint editor fill tools.
Fix: Updated all getContext('2d') calls (in the loupe, video provider, and costume display) to include { willReadFrequently: true }. This tells the browser to optimize for frequent reads, making things much faster.
4. Touch Scrolling Felt Laggy
Chrome and WebView warn when non-passive event listeners are used on scroll-blocking events like touchstart. This can make scrolling feel sluggish.
Fix: Updated global touch handlers to use { passive: true }, letting the browser scroll immediately without waiting for JavaScript.
What We Learned
Cross-platform development isn't just about writing code — it's about understanding the subtle differences in runtime environments. A standard browser API like FileReader or Canvas2D can behave slightly differently in a WebView than in a desktop browser, and those differences can cause major issues in complex apps.
Key takeaway: Make sure your "save" logic works reliably across all input types (touch, mouse, keyboard), and don't hesitate to polyfill environment gaps to keep your libraries happy.
Top comments (0)