The one tool with no card gets one — but only at the ring. Setting a timer stays a capsule; time running out becomes a card, in the same grammar as every other tool bubble: band · setter · watermark. Every specimen below carries room-ui.html's own CSS, verbatim, in both themes.
_clock_fire read only by/by_slug off the clock, so a persona's face arrived and a human's did not.t("Clock") is the ONE WORD the drawer tile and the ◷ panel already use for this tool, and the v647 naming batch's rule is one door per concept — three surfaces naming the same object may not disagree. Every specimen below has been re-rendered with the shipped word.Three capsules, one builder (buildClockCap): set · cancelled · rang. They are the same object at three volumes.
light · today
dark · today
The second capsule becomes this. The first one does not change — setting a timer is a move, and a card for it would be a card nobody is asked to do anything with.
light · the ring
dark · the ring
| part | what it says | source |
|---|---|---|
| band — icon + title + badge | Timer, and the state beside it | toolBand(), accent --clay — the timer's palette colour since v651 |
| watermark | the clock glyph, 150px, 10%, −18° | toolWatermark("clock") — unchanged, one line |
| setter | avatar + name in the seat colour | gateOpener(). ⚠ the ring event does not carry by_uid today — a human setter would lose their face. Server fix required. |
the label — .gc-q | 「自由讨论」— what the phase was for | the sheet's What is it for? field, ≤30 chars, optional |
the digits — .gc-ran | ran 5:00 · rang at 14:32 | the ring event's sec + ts. One new CSS rule; everything above is existing classes. |
Each was a real fork. Both sides are still rendered — the losing option is kept as the record of what the choice was made against.
The card wears .reveal: one glow burst as it lands, ✦ twinkling three times, then it settles. It is the revealed treatment — the same one a poll's result and a deposit's opening get. Why I lean here: the ring is an interrupt. The phase is over and the host has to move; a record that arrives silently is the problem this card exists to fix. And the burst is one-shot per card (v610), so scrollback stays quiet.
light
dark
The closed badge: muted on --surface-2, no burst, no ✦. The argument for it: the ring already has three other channels — the top bar's ◷ flips to「Time's up」for six seconds, the panel gets a cue turn and speaks, and (installed) a push notification fires. A fourth shout in the stream is the fourth time you are told. This card would then be pure scrollback: what the phase was, who set it, how long it ran.
light
dark
Exactly the poll's grammar: the band says Timer and nothing else (v610 — the title is the tool's NAME, the badge beside it says the state), and 「自由讨论」 sits where a poll's question sits, at 16px. Why: the strip chip, the band and the card must not disagree about which object this is, and「Timer」is the only string that is true for every timer.
The DoD's address ruling says the title IS the address, and the strip already renders a clock chip with its label as its name (e.tool === "clock" ? e.title : …). Under B the band reads「自由讨论 · TIME'S UP」and the 16px line is dropped. Against it: a timer with no label — which is the default, the field is optional — leaves the band empty. And the timer is a singleton: there is only ever one, so it never needs an address to disambiguate it from a second one.
light · B, and B with no label
dark · B, and B with no label
The field is optional, so this is the common case, not the edge one. Left: the line is simply dropped and the card is three rows tall. Right: it falls back to「Time's up」— which then says it twice, once in the badge and once as the headline.
light · drop it (picked) vs repeat it
dark · drop it (picked) vs repeat it
Four setters × label / no label. These are the ones that exist — there is no「server-set」timer, because a clock is always set by somebody(the panel via <clock/>, or a human through the sheet).
light · the four
dark · the four
The fourth is a long label — the sheet caps the field at 30 characters, and anything past ~19 CJK glyphs takes a second line. It wraps rather than truncating, which is the poll question's behaviour and the right one here too: a phase name you cannot read is not a record. The card grows; nothing else moves.
| where | change | as shipped |
|---|---|---|
run_room.py · _clock_fire | the clock_ring event and its SSE payload carry by_uid — they carried only by / by_slug, so a human setter reached the card with no face and no colour while a persona's was fine | 3 lines ✓ |
run_room.py · replay | the clock_ring branch passes by_uid through. A pre-v652 ring has none stored, and gateOpener degrades to the tool's own glyph with the name intact — never to a blank | 1 line ✓ |
room-ui.html · buildClockCap | kind === "ring" returns a card (buildClockRingCard); set / clear keep the capsule. The card is toolWatermark + toolBand + gateOpener + the label + the digits — every one an existing builder | ~20 lines ✓ |
room-ui.html · renderClockCap | branches on which object it built: a card gets watchReveal(), a capsule keeps pulseIfVisible(…, "pulse2"). ⚠ pulse2 is a .joincap rule — leaving it on the card would have been a silent no-op and the card would have landed with no arrival cue at all | 2 lines ✓ |
room-ui.html · toolBand | a new badgeTx — a badge-word override for any state, because the ring wears the revealed treatment while saying「Time's up」. A ring is not a reveal. (closedTx stays as it was; it is the closed-only case and has its own callers.) | 1 line ✓ |
| CSS | .gate-card .gc-ran — the one new rule | 3 lines ✓ |
| i18n | two new keys: ran {dur} · rang at {time} and its no-legible-duration fallback rang at {time}. Clock, Time's up and set by {name} were all already in the dict — which is the naming batch paying for itself | 2 keys ✓ |
| not changed | the top bar's ◷ six-second「Time's up」beat, the panel's cue turn, the push notice, the set / cancelled capsules | — |
buildClockCap — persona / human / no-label / pre-v652 / long label / no legible duration, plus both capsule controls, which stayed capsules.