Commit Graph
5 Commits
Author SHA1 Message Date
hansdezwartandClaude Opus 5 998009629b Say "Out of time", and stop the sheets shadowing the clock
Two things Hans spotted playing on the phone.

A blackish gradient sat across the bottom of the screen. Both sheets are
fixed to bottom:0 and pushed off with translateY(101%), but their
box-shadow is thrown 18px *upward* with a 50px blur — so a closed sheet,
sitting 1% below the viewport, blurred darkness back onto the clock and
left it there, twice over, once per sheet. The shadow now only exists on
.sheet.on. Down one column the bottom used to fade 154 to 111 over the
last 70px; it is flat 154 to the edge. An open sheet still casts exactly
what it did.

A flagged clock now reads "Out of time" over two lines in white instead
of showing 0:00, on the red the panel already turned. Sizing it off the
viewport would not work: the score lines above eat into what is left, so
a 5-point match has less room than a 1-point one on the same phone. The
stack is a size container and the words take the smaller of 23vw and
42cqh — two lines at line-height 1.04 need 2.08x the font size, so 42% of
the container leaves a tenth spare. Measured in real viewports it lands
between 52px on a 320x568 at five points and 95px on a 412x915, fitting
every combination; with two lines it is the width that binds first, "Out
of" being the long line. The other half keeps showing its own time.

Checked that normal play still shows clocks and hides the words on both
panels, and that Reset puts the flagged panel back to its clock.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 20:05:24 +02:00
hansdezwartandClaude Opus 5 11ec616270 Add the MIT licence and the F-Droid listing
"Do whatever you like with it" isn't an SPDX identifier, and without one
F-Droid won't take the app at all. Same intent, now in a form a machine
can read.

The listing lives in fastlane/metadata/android/en-US/ so F-Droid reads it
out of the repo and it stays in version control: title, a 65-character
summary, a description adapted from the README that leads with the empty
permission list, a changelog and four screenshots.

The screenshots are generated from the same HTML the app runs, at
1170x2532. The harness freezes the render loop once the wanted frame is
painted — a headless capture otherwise lands whenever the virtual clock
runs out, by which time the delay bar has always finished draining, and
the delay is the thing worth showing. Shot one is a 5-point match at 2-1
with the bar half spent; the others are the score sheet, the settings
sheet from a pristine match (the gear is gone once a match is running, so
that is the only honest way to show it), and a 1-point game with the
score chrome absent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:28:05 +02:00
hansdezwartandClaude Opus 5 6069ef270e Drop the haptics
The clock buzzed on every turn change, on a flag and on the confirming
second tap of Reset. Sound and the colour change carry all of it, so the
vibration goes: buzz() and its four call sites, and the iOS README bullet
that explained why the buzz was silent there — a platform difference that
no longer exists now there are no haptics anywhere.

Verified by stubbing navigator.vibrate and driving a turn change, a
timeout and a confirmed reset: zero calls, while the turn still counted
and the flag still fell.

It also means the Android package can declare no permissions at all.
VIBRATE was the only one it would have needed — there is no INTERNET
either, since the whole clock ships inside the APK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 19:10:23 +02:00
hansdezwartandClaude Opus 5 2c31c0f02b Move the presets under Delay and give them a heading
They sat between Match and Time as three bare buttons, above the two
settings they set. Now they follow Delay, after the numbers they are a
shortcut for, with a "Preset time limits" heading and "Quickly pick a
setting." — the same heading-and-description shape every other row in the
sheet already has.

The row stacks at every width rather than only under the .row--wide
breakpoint: three buttons wide enough to read "3m / 15s" can't share a
line with a label on any phone.

The buttons themselves are untouched, and are still found by class rather
than position, so the highlight logic came along unchanged — checked that
opening the sheet lights the preset matching the current numbers,
stepping the delay off it clears every highlight, and stepping back
relights it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 18:11:04 +02:00
hansdezwartandClaude Opus 5 261cebd10b Charge the hold, and drop the two buttons that have nothing to do
Three things, plus the README moves up to the repo root where a README
belongs — it was being served as part of the site.

The clock now runs until the finger lifts. The previous commit registered
a tap on the lift but backdated the turn to the press, which showed up as
the display counting down during a hold and then jumping back. Worse than
cosmetic: the hold was refunded, so a thumb resting on your own half
bought unlimited thinking time for nothing, and holding past zero
couldn't flag you either, because render()'s flag check watches the live
display while tap() charged from an earlier instant. One
performance.now() at the lift now serves both the outgoing charge and the
incoming turnAt, so nothing falls between them and goes to neither
player. With the delay at 0 and a turn 1000ms old, an instant lift costs
1001ms and a 600ms hold costs 1602ms — the inverse of what the last
commit was verified against. Swipe rejection is untouched; it lives in
the pointer handler, not here.

Reset and pause step out when they have nothing to do: pause before each
game's first tap, reset while the match is still pristine. matchPristine()
already meant exactly that, so both toggles sit beside the settings one in
render(), where they can't go stale. Reset and settings turn out to be
exact opposites. btn--vacant like the gear, so the space is kept — a
fresh-match bar differs from the old build only inside those two slots,
every other pixel in the frame identical, gear and speaker unmoved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 17:47:50 +02:00