WebSerial lags when drawing line in Flipper Zero paint app
Categories
(Core :: DOM: Device Interfaces, defect, P2)
Tracking
()
People
(Reporter: gstoll, Unassigned)
References
(Blocks 1 open bug)
Details
Navigate to https://lab.flipper.net
Click Connect
Choose “Flipper Aik0r0” and click “Allow”
Switch to the Paint section
Using the default Pencil tool, click the mouse down, move the mouse to draw a line, and release the mouse button
While the mouse is down, the line will not draw, which is wrong. After releasing the mouse button, the line will draw correctly in the web browser, but the line will not draw on the Flipper Zero. (the next time you draw something, the Flipper Zero will update correctly)
| Reporter | ||
Updated•1 month ago
|
| Reporter | ||
Comment 1•1 month ago
|
||
I think what's happening is that the Flipper Lab source code is inefficient, causing it to tie up the main thread of its content process and delaying the serial calls. Here's what Claude says:
Found it! The culprit is in the Flipper Lab app's imageDataToXBM() function in shared/lib/utils/pixeleditor/xbm.js.
The Bug
On every sendFrame() (throttled to 100ms during drawing), imageDataToXBM() converts the 128x64 pixel canvas to XBM
format. The inner loop is very inefficient:
for (let c4 = 0; c4 < 256; c4++) {
if (JSON.stringify(xbmValues[String(c4)]) === JSON.stringify(hexBits)) {
xbmBytes.push(c4)
}
}
For each of the 1024 bytes in the XBM output, it brute-force scans all 256 possible byte values, comparing arrays via
JSON.stringify(). That's ~524,288 JSON.stringify() calls per frame, synchronously on the main thread.
Why Firefox Is Worse Than Chrome
Both browsers run this code, but SpiderMonkey's JSON.stringify() on small arrays is apparently significantly
slower than V8's, pushing the total time from "noticeable but tolerable" in Chrome to ~2 seconds in Firefox.
The Call Chain
mousemove → handleInteraction() → sendFrame() → imageDataToXBM(imageData) → 524K × JSON.stringify() → main thread
blocked → no mousemove events delivered
The Fix
The entire 256-iteration JSON.stringify comparison loop can be replaced with direct bit manipulation:
let byte = 0;
for (const bit of hexBits) {
byte |= (1 << bit);
}
xbmBytes.push(byte);
This eliminates all JSON.stringify calls entirely, turning an O(256) linear scan with serialization into O(8) bitwise
OR. The xbm-values.js lookup table becomes unnecessary.
This is a bug in the Flipper Lab app, not in Firefox or WebSerial. That said, it might be worth filing a SpiderMonkey
bug about JSON.stringify performance on small arrays since the performance gap with V8 is significant enough to cause
real-world breakage.
| Reporter | ||
Comment 2•1 month ago
|
||
Actually, this doesn't happen on the Mac, and the latest changes we have to more efficiently use the serial thread on Windows seem to make this go away. So once bug 2010930, I'll check this one more time and we can probably close this.
| Reporter | ||
Comment 3•7 days ago
|
||
This issue is back but it only seems to happen on Windows. Given that this is a pretty unusual app, I think we can be OK shipping with this.
Description
•