A minimized game says it is your move

Featurekamo-internal
Shipped
September 9, 2026 at 2:32 AM UTC
Author
Kamo
Commit
563bc3f

A head could already say a message had arrived. It could not say a game was waiting on you — chess tinted its border brass, which on a forty-pixel hexagon at the corner of the dock is not an event, and Hold'em said nothing at all. Heads now carry a turn. It is deliberately not an unread count: a number on a chess head reads as unread messages and there are none. What the member needs to know is that it is their move, which is a state rather than a quantity, so the head's own outline says it and breathes while it is true. Hold'em's turn has a clock, and the clock is drawn as that outline draining — green, then amber, then red — against a dim track. A head is a shape with a strong outline already; a rectangular bar bolted underneath would be a second object to find at a size with no room for two. **The countdown is a CSS animation, and that is the whole design.** The obvious build is a 200ms interval writing a fraction into React, which is what the felt's own ring does and is right there — it is on screen inside a component already re-rendering. A head is not. It floats over the application on a physics-driven layer that moves hexagons around, it outlives the window being minimized, and it is very often on a tab nobody is looking at. So the ring is one keyframe animation whose duration is the whole allowance and whose animation-delay is NEGATIVE by however much has already gone: the browser starts it part-played, runs it on the compositor, and keeps it exact whether or not anything re-renders and whether or not the tab is in front. A timer there would be a re-render of the whole floating layout several times a second, and Chrome throttles a hidden tab's timers to one wake-up a minute — a clock that stops when you look away and jumps when you come back is worse than no clock, because it is one you would have trusted. The head and the felt agree about WHEN each stage begins, because the seconds half of `clockPressure` is converted into fractions once per turn. They differ only in colour, and on purpose: the felt ramps through brass because brass is the table's accent, and a head sits on the application chrome with no card room around it to make brass mean anything. Two things a browser found that reading could not: - The step between colours was written as two keyframe stops at the same percentage. CSS keeps only the last rule for an offset, so the pair collapsed and the ramp became one long blend: at five seconds left the ring painted rgb(244,91,46), a mixture of amber and red rather than either, on the one part of the ramp that is supposed to be an alarm. - The "your move" ring stayed green underneath the countdown, so three seconds from a fold the head was a green hexagon with a small red tick on it. It is the track the clock drains against now, and dim. And the deadline PASSING is a state change rather than a comparison, because nothing re-renders when it passes and `holdem.member.*` has no stream behind it — a lost fold frame would otherwise leave a head breathing an empty red ring about a hand somebody was folded out of a minute ago. One timeout per turn. Hold'em's own dispatch is not in this commit: HoldemTool is held by another session. Chess is wired end to end.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing