Spaces:
Sleeping
Sleeping
Commit History
-
fix(fe): suppress cushion-snap when a ball sits at the apex
A track turns round off a rail or off a BALL and near a cushion the two look alike: shot_02's cue turns 152 degrees 10.3 cm off the far rail with the 5 sitting 6.9 cm away. collisions calls that kink and shot_05's real bounce `unknown` alike, so the veto reads the layout in both places the picture holds it. shot_02 1 snap -> 0 (50 canvas pixels, all in the removed segment); shot_05 canvas byte-identical.1e61cc4 -
feat(fe): dashed cushion-snap for near-rail turnarounds
A ball pressed against a cushion is half hidden by it, so its bbox centre reads ~6.5 cm short and the drawn line turns round in mid-air -- shot_05 apexes at y 2.4464 with the rail at 2.54. The measurement cannot move (the fix is full boxes on the ND1 line), so the DRAWING closes the gap: an apex within CUSHION_SNAP_M 0.12 of its nearest rail that turns at least 90 degrees gets a dashed segment out to that rail, the same language the pocket-bound stretch uses. JSON unchanged. Accepted on the DOM: shot_05 ends on the rail pixel row, shot_01 and shot_03 grow nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>4f0b4f3 -
feat(fe): draw ghost rack when rack_guess is on
The break frame comes back with four or five of nine balls -- the rest are physically hidden behind them at this camera angle. The JSON keeps measurements plus one flag, so the missing balls belong to the drawing: a dashed, faint diamond under the balls that were really seen. Gate: 3 contract tests; toDataURL diff shows all 9 ghosts plus the caption and leaves every measured ball pixel untouched.3d87b03
-
feat(fe): extrapolate pocket-bound balls into the pocket on replay
Measuring stops where the detector gave up, so a pocket-bound ball stalled on the cloth. The replay now rolls it the last stretch at the speed it was last seen doing, and the table view draws that piece DASHED so measured and inferred never look alike. Drawing only -- nothing is written back. Gate: shot_03 replay ends 0 cm from the pocket against 23.75 cm short before; pytest 213 app / 227 cv.36d3768 -
feat(fe): draw and replay object-ball tracks on the table view
The table view showed only the cue moving while the JSON already carried every ball. Tracks are resampled onto one even time base before animateShot, which interpolates by index -- untouched, so the collisions still land where they landed. A numberless ball is grey, not a second white cue. Gate: pytest 194/208 green; verified live (paths at 0.6 alpha, potted fade, no ghost ball: 145 vs 279 px).b0d16f3
-
fix(fe): shorten the cpu warning note
Four sentences of caveat before the first shot list; two carry the same information (how slow, what fills in, that a sample is already there). No test locked the old wording, so no gate key changed.a0fcbb6 -
chore(repo): normalize line endings with text=auto
The tree mixed CRLF and LF with only *.bat declared, so an English-only edit produced a 3704-line diff and every commit needed its EOL restored by hand. Content is untouched: git diff --ignore-cr-at-eol shows .gitattributes alone. pytest 160+7skip (app) / 167 (cv), 3 runs each.2cfc662
-
fix(fe): scope the viz caption width cap to the ball column
`max-width: 120px` sat on `.viz-cap` itself, so the caption in the wide right-hand column was squeezed too and broke one sentence over five cramped lines. The cap now belongs to the ball column alone, and a non-breaking space keeps "0.37 down" from splitting. Gate: pytest 160 passed + 7 skipped, 2 runs; label 120px/5 lines -> 250px/2, hero 226px -> 181px tall, 258 -> 215 at 375px, no overflow. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>faf3aa9 -
fix(fe): reword hero captions in viewer-facing words
A dot at the top right captioned a=-0.20 reads backwards to anyone watching the ball, so the caption now says "0.20 right, 0.27 up" through one contactWords the quickbar shares. The convention is unchanged and the signed pair stays in the numbers table, which also takes the checkpoint name the viewer-facing label no longer carries. Gate: pytest 160 passed + 7 skipped, 2 runs; 167 collected, unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>da71d35 -
fix(fe): unflex an-note and flatten drawer background
A second `.an-note` block overrode only the type, so `display: flex` from the illustrated-note rule leaked into every note and laid prose out as flex items -- the "hard to read" Danh saw. The flex layout is now its own class, the two prose notes are two sentences each, and the drawer drops its lighter ground so the panel reads as one surface. Gate: pytest 160 passed + 7 skipped, 2 runs; every plain note is block. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>2bdb082 -
fix(fe): replace corrupted details marker with css caret
The Technical details summary carried a mangled escape in `content` (0x15 followed by "B8"), which rendered as a broken box. The marker is now a triangle drawn from borders that rotates 90 degrees when open -- no glyph, no font dependency, nothing left to mangle. Gate: pytest 160 passed + 7 skipped, 2 runs; computed content is empty and the open state measures matrix(0, 1, -1, 0, 0, 0). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>15641ee -
feat(fe): simplify shot list to spin and power columns
Eight debug columns asked a player to read V0, phi, a/b and RMSE; the list now shows what spin and how hard, and those numbers stay one click away on the detail page under Technical details. Contract test rekeyed to the five columns per the 24/08 design decision, not loosened: the old headers are now asserted ABSENT. Gate: pytest 160 passed + 7 skipped, 2 runs; demo 14 rows checked. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>dded2ea -
feat(fe): collapse technical numbers behind details toggle
The model-versus-analytic table, warnings, re-simulation toggle and raw JSON link are moved, not rewritten, into one closed "Technical details" drawer, so the hero is what the page opens on. A shot with no parameters forces it open -- the reason inside is then all there is. Gate: pytest 160 passed + 7 skipped, 3 runs; drawer checked by hand on the demo (closed by default, resim toggle and RMSE line unchanged). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>af94a97 -
feat(fe): always-on spin+power hero on shot detail
A player reads two things: what spin and how hard. The widget carrying both waited for a replay, so the page opened on debug numbers instead. It now leads the page whenever the shot has a shotnet block, with a plain-English gloss and a POWER_TIERS label beside the m/s figure. Gate: pytest 160 passed + 7 skipped, 3 runs; demo 14 shots checked by hand (hero, caveat, downgrade badge, suspect box, mobile quickbar). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>feffb09 -
chore(fe): remove dead CSS rules of the removed tabs
The suggestion engine, drills, QR and TV sections went at the port but their styles stayed, so reading style.css suggested UI that does not exist. Gate: 184 -> 103 rules (81 cut), style.css 904 -> 567 lines, braces balanced; computed styles of every element across list, detail, corner overlay and quickbar at 1280x800 and 375x812 are unchanged (0 of 423 differ). Kept: .anv-badge-* and .banner.error/warn/win, both built at runtime. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>6aaba6f -
refactor(fe): translate front-end UI strings to English
Second half of the one-language decision: the server already speaks English, so the page had to follow or the app would read as a mix. Gate: pytest 68 passed; 0 Vietnamese lines left outside demo_analyzer; id/class multiset and tag sequence of index.html identical to HEAD (109 attributes); list and detail pages read clean, no console errors. Also carries the CLAUDE.md language rule and the new `fe` scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>fae8ae3 -
refactor(analyzer): translate identifiers and comments to English
Comments, docstrings, identifiers and test names are now English, including the Dockerfile and .dockerignore reasoning. Strings the user reads stay Vietnamese, because the product's UI language is Vietnamese: HTTP error details, per-shot reasons, warnings and the CSV headers. Semantics are unchanged -- an AST comparison with string constants blanked is identical for every module except three renamed locals; pytest 68 passed.876aff5 -
feat(analyzer): port analyzer pipeline from poolcoach-rl
Traced the import graph from the Analyzer routes: app store/transport/ embedded worker, src/poolcoach_cv end to end, cv_worker, the multi-shot contract test, the packaged demo video and the Hugging Face deploy set. The suggestion engine, drills, QR/TV and the image-scan job stay behind, so their routes, schemas, tables and front-end sections are gone with them; /api/table now reads pooltool directly (src/poolcoach_sim/table.py).da25347