feat(#44): show a reduction % on every folded block and group#48
Conversation
Add a small reduction-percentage tag (whole-% of tokens removed) so users can read how aggressive each fold was, across all three fold surfaces. - engine/tokens.ts: pure `reductionPct(full, live)` helper (saved/full*100, divide-by-zero -> 0); unit-tested in tokens.test.ts. - Map canvas (tileDraw.ts): a `reductionPct?` field on TileSpec + a cached offscreen-sprite badge (rounded to nearest 5% -> <=21 sprites, blitted like the dice/hatch sprites - no per-tile fillText/filter/gradient). Drawn inset at the tile bottom, Smoke mono, only on folded blocks and collapsed-group tiles. - ContextMap.svelte: compute reductionPct in buildTilesSpecs/protSpecs; add a Smoke-mono `.cell-pct` badge to sliver-mode summary tiles and the open-group parent (peeked = folded); add a `−N%` badge to transcript folded cards; surface the % in the tile/group/fold tooltips. - Inspector.svelte: `−N%` in the token data row for folded blocks and groups. Brand: Smoke (#9A9A9A / --muted) mono only - never a spectrum hue, never on a live tile, faint so the folded tile stays recessed and calm. Defaults change nothing for users who never fold. Closes #44.
…an't render negative reductionPct(full, live) documented and displayed as "percent of tokens removed" did not clamp. A conductor substitution LARGER than the original block returned a negative value (reductionPct(100, 150) = -50), which rendered as a stray minus sign on every fold surface (tooltip, foldTip, sliver badge, transcript badge, Inspector token row) since those sites emit the value unconditionally for folded blocks. Clamp at the helper so all surfaces are correct by construction, and make the defensive test assert exact bounds (0 for oversized, 100 for fully removed / negative live).
|
Thanks for the review — finding addressed in 071d672. You're right: Fixed at the helper (one place, so every surface is correct by construction): export function reductionPct(full: live: number): number {
if (full <= 0) return 0;
const pct = Math.round(((full - live) / full) * 100);
return Math.max(0, Math.min(100, pct)); // clamp to documented [0, 100]
}The defensive test now asserts exact bounds — I deliberately did not add Re-verified: |
Tile badges (Map canvas sprite + sliver/open-group DOM spans) now show a single 0-9 digit — drop the ones place, keep the tens digit of the reduction %, clamped to 9 for a fully-removed (100%) fold. Tooltips, the Transcript row, and the Inspector panel keep the precise "-X%" text.
Every number added in this PR now reads as "how much of the original content is still on the wire" instead of "how much was removed": tokens.ts's reductionPct/reductionDigit become remainingPct/remainingDigit (live/full x 100, clamped [0,100]; a zero-token block reads as 100% - fully intact, matching the "nothing to remove" case). The tile badge digit, tooltips, Transcript row (renamed .tr-remaining), and Inspector panel (renamed .tok-remaining) all switch accordingly, dropping the leading minus sign in favor of "X% remains" copy since the number is no longer a delta.
Both render paths (canvas sprite in tileDraw.ts, DOM .cell-pct span in ContextMap.svelte) shift from bottom-centered to top-right, inset 1-2px.
…on border The digit badge collides with dice pips at every corner once a tile reaches face 4+, so drop it in favor of a border that lives at the tile's true edge (the one region the pips never touch). remainingBand buckets remaining-token pct into 6 stepped sizes (full >=90, 90-75, 75-50, 50-25, 25-10, empty <10); both the canvas (tileDraw.ts, cached sprite per band) and DOM/sliver (ContextMap.svelte, inline SVG) renderers share the same erosionArmLength geometry so the two paths stay pixel-consistent. Applied to individually folded blocks and group summary tiles only. The border is drawn before the pinned/selected/inrange rings so those rarer, more important states always paint on top when they coincide. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… % remaining Live blocks/groups keep their existing richer tooltip (tool name, action hint). Anything already degraded — a folded block, a folded or drop group, a peeked group — now shows only the 3 fields that matter once something's gone: kind, original token count, precise % remaining. Backed by a single shared minimalTip() helper so all 4 call sites (tip, foldTip, groupTip, the open-group peek title) stay consistent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Closes #44.
What
Adds a small, on-brand reduction-percentage tag to every folded block and folded (collapsed) group so users can read how aggressive each fold was — light or heavy. Shows % of tokens REMOVED (
saved / full × 100, rounded to a whole percent), consistent with the existing Map-header "saves X tok" copy.Brand & taste (read brand/accordion-brand-kit/brand.md first)
--muted(#9A9A9A, the brand "labels, metadata, fold states" color) on IBM Plex Mono. Never a spectrum hue, never blue (blue is reserved for user blocks), never on a live tile. The tag keeps the folded tile's recessed, drained calm (the ci: cross-platform release workflow (Tauri installers) #1 brand signal) — information, not decoration.Three surfaces
engine/tokens.tsreductionPct(full, live)— divide-by-zero → 0; unit-testedui/map/tileDraw.tsreductionPct?onTileSpec; cached offscreen sprite per rounded-5% value (≤21) blitted withdrawImage— no per-tilefillText, nofilter/gradient (CLAUDE.md perf rule). Drawn last, inset at tile bottomui/map/ContextMap.sveltereductionPctinbuildTilesSpecs+protSpecs(folded blocks + collapsed groups)ContextMap.svelte.cell-pctSmoke-mono badge on summary tiles (ungrouped fold + group cocoa + peeked open-band parent)ContextMap.svelte−N%(.tr-reduction) on folded cardsContextMap.sveltetip/groupTip/foldTipinclude−N%Inspector.svelte−N%in the token data row for folded blocks and folded groups (.tok-reduction)Data (pure reads, no wire change)
reductionPct(b.tokens, store.effTokens(b)).reductionPct(store.groupFullTokens(g), store.groupLiveTokens(g)). A drop group → live 0 → 100%, signalling "the agent does not see this block".Design calls left to the owner (made restrained defaults; flagged in case the screenshot loop wants to change)
85), not−85%— a ~20px tile can't legibly fit 4 chars. The Transcript/Inspector/tooltips carry the full−N%form, which establishes the number's meaning. A different glyph is a one-line sprite change.Verification
cd app && npm run check→ 0 errors / 0 warningscd app && npm run test→ 41 files, 809 tests passed (incl. newtokens.test.ts+ 2tileDraw.test.tsTileSpec cases)npm run dev(port 1420 may be busy; UI is for the owner's screenshot review).