measuring stick + integer snap on release - #9
Merged
Conversation
Replaces PR #8's gauge (live arrow + two fading reference ticks) with a different intervention: a persistent 0–10 ruler on each funnel and integer snapping at commit time. Net result: clean integer states, a visible scale, no decimals to parse. Why --- The live indicator from #8 duplicated the under-funnel readout, the reference ticks hid during pours (when spatial reference matters most), and decimal vote counts ("5.9 votes 34.8 credits") cost more in legibility than they gained in honesty. The brief asked for a different shape entirely. What's added ------------ - A persistent 0–10 ruler on the outer right edge of each funnel. Major ticks with labels at 0/2/4/6/8/10; minor ticks (no labels) at 1/3/5/7/9. Always visible, no fade behaviour, no isAnyPouring plumbing. Tick marks point left toward the water; labels sit just right of the axis. Vote-axis is linear in height (votes = water height), so ticks are evenly spaced — the quadratic lives in the credits readout, not the ruler. - snapVotesToInteger(live, item, votes, budget) in math/qv.ts: committed = clamp(round(live), 0, ⌊√budget⌋, ⌊√(budget − Σothers²)⌋) Round-half-up, then clamp DOWN if the rounded value would overdraw — the brief's two edge cases (release at 9.6 with others holding the pool, release above the cap) both fall through to the clamp. What's removed -------------- - The live indicator from PR #8 (left-pointing arrow + numeric label on the right edge). - The two reference ticks at votes = 5 and 10 with the fade-during-pour cross-fade. - GAUGE_W (36 px) reservation past the V's right edge — the funnel cavity returns to its pre-#8 proportions; the ruler lives in extended viewBox width past the V's right edge. - The `isAnyPouring` prop wiring from LiquidQV → Funnel. No state needs to follow the global pour anymore. - All decimal display: under-funnel readout, pool readout, ARIA values are integer everywhere. The display formatter `fmt(n)` now returns `Math.round(n).toString()`. Underlying `votes` may still be fractional during a hold (the live derivation), but every visible number rounds at the boundary. What's preserved ---------------- - The hold-to-pour gesture mechanics — constant volumetric rate, water rises smoothly and slows visibly as the funnel widens. This is still the load-bearing pedagogy: only the *committed* value is integer, not the in-flight motion. - The 2D triangle funnel rendering (post-#7 revert state). - Conservation invariant — pool + Σ votes² = budget — now expressed in integers at rest. - Pool reservoir, pour stream, intro copy, on-load explainer, footer disclaimer, default ballot. Verified end-to-end ------------------- - All funnels at 0 → ruler visible (0/2/4/6/8/10 labels + minor ticks). Pool reads "100 / 100 credits". Each card reads "0 votes 0 credits". - Hold + on Harris ~1.5 s → on release, snaps to "3 votes 9 credits"; pool drops to "91 / 100 credits". Conservation holds. - 33 tests passing (was 29; added 4 new for snapVotesToInteger including both round-up clamp-down edge cases). ESLint clean, typecheck clean, all three build targets succeed, no console warnings during interaction. Docs ---- docs/round-11/README.md describes each state with the verified DOM snapshots from the live preview.
✅ Deploy Preview for liquid-qv ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces #8's gauge (live arrow + two fading reference ticks) with a different shape: a persistent 0–10 ruler on each funnel, plus integer snapping at commit time. Net result: clean integer states, a visible scale, no decimals to parse.
The hold-to-pour gesture stays — water rises continuously and slows visibly during a hold, and that's still the load-bearing pedagogy. Only the committed value is integer.
Why this differs from #8
The live indicator from #8 duplicated the under-funnel readout, the reference ticks hid during pours (when spatial reference matters most), and decimal vote counts (
5.9 votes 34.8 credits) cost more in legibility than they gained in honesty. The brief asked for a different intervention entirely.What changed
Removed (from #8):
GAUGE_W = 36reservation past the V's right edge — funnel cavity returns to pre-measuring-stick: per-funnel gauge #8 proportions.isAnyPouringprop wiring fromLiquidQV→Funnel.fmt(n)returnsMath.round(n).toString().Added:
0/2/4/6/8/10(1.5 px stroke, 10 px length).1/3/5/7/9, no labels (1 px stroke, 5 px length).snapVotesToInteger(live, item, votes, budget)insrc/math/qv.ts:Round-half-up, then clamp DOWN if the rounded value would overdraw. Two edge cases pinned by tests:
b = 5(others using 25 credits, available = 75) → round = 10 → clamps to⌊√75⌋ = 8.b = 4(others using 16, available = 84) → round = 10 → clamps to⌊√84⌋ = 9.endPourinLiquidQVnow callssnapVotesToIntegerinstead ofclampVotesAgainstBudget. The reducer still floors any fractional input it receives as defence-in-depth.What's preserved
pool + Σ votes² = budget— now expressed in integers at rest.Verified end-to-end
0/2/4/6/8/10labels + minor ticks). Pool reads100 / 100 credits. Each card reads0 votes 0 credits.3 votes 9 credits; pool drops to91 / 100 credits. Conservation holds.snapVotesToIntegerincluding both round-up clamp-down edge cases).tsc -b --noEmitclean, all three build targets succeed, no console warnings during interaction.Files touched
src/math/qv.ts—maxVotesreturns⌊√budget⌋again;clampVotesAgainstBudgetfloors fractional input; newsnapVotesToInteger.src/math/qv.test.ts— integer-cap behaviour reasserted; newsnapVotesToIntegerblock (4 tests).src/components/Funnel.tsx— gauge layer removed; funnel cavity restored; 0–10 ruler added in extended viewBox space past the V's right edge.src/components/LiquidQV.tsx—snapVotesToIntegerinendPour;fmtis now integer;isAnyPouringprop dropped.src/components/CreditPool.tsx— readout usesMath.round.docs/round-11/README.md— state descriptions with verified DOM snapshots.Screenshots
GitHub doesn't accept binary uploads via
gh pr create, and the preview environment couldn't reliably render clean image captures for this round (viewport / scroll quirks).docs/round-11/README.mdon this branch describes each state with the verified DOM-level evidence. To see it live:npm run dev.Test plan
npm install && npm run dev3 votes 9 credits, pool to91 / 100 credits.4 votes 16 credits(clearly less progress for the same hold duration — the lesson, intact).npm test && npm run lint && npm run typecheck— green.Don't merge
Per the brief: hold for review.
🤖 Generated with Claude Code