Issue
The Voronoi stippling animation in an Astro-based frontend caused visual distraction and performance overhead. During page load, 80 intermediate frames of Lloyd’s relaxation algorithm were rendered progressively, creating a ‘fizzling in’ effect that lasted approximately 2-3 seconds. This animation was unintentionally interpreted by users as an indication of ongoing computation rather than a deliberate design choice, leading to confusion and unnecessary perceived loading time.
Culprit
The issue stemmed from a mismatch between the algorithm’s nature and the implementation design:
-
Progressive Rendering: Each of the 80 iterations of Lloyd’s relaxation was sent from the Web Worker to the main thread via
postMessage(), triggering an immediate canvas re-render. This caused the progressive display of intermediate states. -
Algorithm Design: Lloyd’s relaxation is a deterministic process where only the final state of the Voronoi diagram matters for visual quality. The intermediate steps were unnecessary for the user experience but contributed to visual noise and performance degradation.
Solution
The solution involved optimizing both the Web Worker and main thread interactions:
-
Web Worker Optimization: The Web Worker was modified to send only the final result of the Lloyd’s relaxation algorithm after all iterations completed. This eliminated the need to send 80 intermediate states.
-
Main Thread Guarding: The message handler on the main thread was updated to render only the final result, avoiding all intermediate renders. An
isFirstRenderflag ensured that the final result was displayed once and the worker was terminated to clean up resources.
Performance Improvements:
- Reduction in message passing: From 80 messages to a single message, achieving a 98.75% reduction.
- Render operations: From 80 canvas renders to just one, achieving a 98.75% reduction.
- Computation time: Remained unchanged, with the process still taking approximately 2-3 seconds to complete in the background.
- Memory usage: The worker terminated immediately after sending the final result, reducing memory overhead.
The final result maintains the same visual quality and computational integrity as the original process, but without the distracting animation or performance overhead.