The board below is running the actual Java engine from a real Android game I built (pre-launch), compiled to JavaScript by TeaVM. Every rule — what counts as a match, what a special gem clears, how gravity refills — is decided by the same Java that runs on the device. This page only draws pixels and forwards your clicks.
The engine decides whether your swap is legal — if no match would form, it refuses, exactly as it does on-device. Match 3+ to clear; the cascade loop resolves until the board settles.
intersection flag in the cascade log.Gem ids are identity keys for the renderer — two gems sharing one animate as a single gem. The engine used to mint them from System.nanoTime() plus a random number. On a JVM that's fine: the clock is high-resolution, and 128,000 gems produced zero collisions. Browsers clamp their clock to ~100µs to mitigate Spectre, so nanoTime barely advances — the same code produced 301 duplicate ids per 128,000 gems here.
Compiling to a second platform is what surfaced it. The fix is a monotonic counter, so uniqueness no longer depends on the clock underneath. Press the button — this mints gems through the live engine and checks every id: