collin/mahjong · 9879b92d
Say where a wall landed, and mean it
Collin Richards · 2026-08-21 22:48 UTC · 9879b92d0c649febbcf977961bf413dfe52e2d21 · parent 40a1e457 · browse files
modifiedsrc/ui/WallRing.tsx+22 −12
| ⋯ 125 unchanged lines | |||
| 126 | 126 | cell: number, | |
| 127 | 127 | ) { | |
| 128 | 128 | const [slide, setSlide] = useState<Nudge[]>(() => [0, 1, 2, 3].map(() => ({ along: 0, across: 0 }))); | |
| 129 | + | // Where the walls are, as the drag knows it. React state is what draws them, | |
| 130 | + | // and it commits when it commits — which is one push behind if the pointer | |
| 131 | + | // has already gone up. This is the same thing, now. | |
| 132 | + | const live = useRef<Nudge[]>(slide); | |
| 129 | 133 | const drag = useRef<{ | |
| 130 | 134 | side: number; | |
| 131 | 135 | ax: number; | |
| ⋯ 4 unchanged lines | |||
| 136 | 140 | } | null>(null); | |
| 137 | 141 | // What the drag needs to know, kept current without the listeners below | |
| 138 | 142 | // having to be torn down and put back on every render to see it. | |
| 139 | - | const now = useRef({ shape, cell, slide }); | |
| 140 | - | now.current = { shape, cell, slide }; | |
| 143 | + | const now = useRef({ shape, cell }); | |
| 144 | + | now.current = { shape, cell }; | |
| 141 | 145 | ||
| 142 | 146 | const moved = () => ring.current?.dispatchEvent(new CustomEvent('wallmoved', { bubbles: true })); | |
| 143 | 147 | ||
| ⋯ 18 unchanged lines | |||
| 162 | 166 | fromAlong: e.clientX * ax + e.clientY * ay, | |
| 163 | 167 | // Across is the wall's own normal: its direction turned a quarter on. | |
| 164 | 168 | fromAcross: -e.clientX * ay + e.clientY * ax, | |
| 165 | - | at: now.current.slide[side], | |
| 169 | + | at: live.current[side], | |
| 166 | 170 | }; | |
| 167 | 171 | }; | |
| 168 | 172 | ||
| ⋯ 10 unchanged lines | |||
| 179 | 183 | along: clamp(d.at.along + (e.clientX * d.ax + e.clientY * d.ay - d.fromAlong)), | |
| 180 | 184 | across: clamp(d.at.across + (-e.clientX * d.ay + e.clientY * d.ax - d.fromAcross)), | |
| 181 | 185 | }; | |
| 182 | - | let changed = false; | |
| 183 | - | setSlide((was) => { | |
| 184 | - | const had = was[d.side]; | |
| 185 | - | if (had.along === to.along && had.across === to.across) return was; | |
| 186 | - | changed = true; | |
| 187 | - | return was.map((v, i) => (i === d.side ? to : v)); | |
| 188 | - | }); | |
| 189 | - | if (changed) moved(); | |
| 186 | + | const had = live.current[d.side]; | |
| 187 | + | if (had.along === to.along && had.across === to.across) return; | |
| 188 | + | live.current = live.current.map((v, i) => (i === d.side ? to : v)); | |
| 189 | + | setSlide(live.current); | |
| 190 | + | moved(); | |
| 190 | 191 | }; | |
| 191 | 192 | const up = () => { | |
| 192 | - | if (!drag.current) return; | |
| 193 | + | const d = drag.current; | |
| 194 | + | if (!d) return; | |
| 193 | 195 | drag.current = null; | |
| 194 | 196 | moved(); | |
| 197 | + | // Said out loud at the end of the push, not during it: what the fingers | |
| 198 | + | // found, in the form it would be written down in. | |
| 199 | + | const at = live.current; | |
| 200 | + | const say = (n: Nudge) => `${Math.round(n.along)},${Math.round(n.across)}`; | |
| 201 | + | console.log( | |
| 202 | + | `[wall] ${WALL_SIDES[d.side]} pushed to ${say(at[d.side])} — ` + | |
| 203 | + | WALL_SIDES.map((cls, i) => `${cls} ${say(at[i])}`).join(' · '), | |
| 204 | + | ); | |
| 195 | 205 | }; | |
| 196 | 206 | window.addEventListener('pointermove', move); | |
| 197 | 207 | window.addEventListener('pointerup', up); | |
| ⋯ 102 unchanged lines | |||