anvilsign in

collin/mahjong

1/**
2 * The collider overlay: every boundary the physics actually uses, drawn in thin
3 * red over the table.
4 *
5 * Everything the tiles bounce off is *measured* off the DOM rather than written
6 * down anywhere — the felt is where the four strips leave off, the wall is
7 * seventy-odd real elements — so the only honest way to check a bounce is to
8 * draw the boxes in the same coordinate space the tiles are drawn in. A bounce
9 * that looks wrong is either a box in the wrong place or a box you had not
10 * thought about, and this tells you which.
11 *
12 * On with `?colliders` in the address bar, or `colliders()` from the console
13 * while a hand is running — which is the point of it, since the thing you want
14 * to look at is usually already skidding across the table.
15 */
16
17const FLAG = 'colliders';
18
19let on = typeof location !== 'undefined' && new URLSearchParams(location.search).has(FLAG);
20
21const listeners = new Set<() => void>();
22
23export const showingColliders = () => on;
24
25/** Toggle, or set. Returns what it ended up as, so the console says it back. */
26export function toggleColliders(next = !on): boolean {
27 on = next;
28 for (const cb of listeners) cb();
29 return on;
30}
31
32/** Repaint when it changes — a settled table is not drawing frames otherwise. */
33export function onCollidersChange(cb: () => void): () => void {
34 listeners.add(cb);
35 return () => {
36 listeners.delete(cb);
37 };
38}
39
40declare global {
41 interface Window {
42 colliders?: (next?: boolean) => boolean;
43 /** The live pool, for poking at from the console. Dev builds only. */
44 pool?: unknown;
45 }
46}
47
48if (typeof window !== 'undefined') window.colliders = toggleColliders;
49
50/**
51 * Hand the console the pool itself, so `pool.world.walls` and `pool.geo` can be
52 * read against what is drawn. The overlay draws the world's own copy rather than
53 * a fresh measurement on purpose — if the two ever disagree it is the world that
54 * is stale, and that is a thing you want to be able to catch.
55 */
56export function exposePool(pool: unknown) {
57 if (import.meta.env.DEV && typeof window !== 'undefined') window.pool = pool;
58}