3 Commits

Author SHA1 Message Date
ghassan
1c4e4986b5 Frame-accurate scrubbing + mobile highlights UX + collapsed action menu
Frame-accurate timestamps (end-to-end)
- Migration 2026_08_08_000002 promotes match_rounds.start_time_seconds,
  match_points.timestamp_seconds, coach_reviews.start_time_seconds and
  coach_reviews.end_time_seconds from INTEGER to decimal(10,3).
- Model $casts updated (float). MatchEventController validators relaxed
  from `integer` to `numeric|min:0` on all four fields.
- Blade SSR data-time-{start,end} attributes cast to (float) so the
  first paint carries frame precision.
- Point + review capture strips: slider step = 1/fps, snapToFrame()
  applied to every seek/nudge/input commit. Clock now shows SMPTE
  MM:SS.FF; parsePcbTimeInput accepts MM:SS.FF, MM:SS, MM.SS or seconds.
- Default fps is 30; override via window.matchFPS.
- confirmPointCapture no longer Math.round()s currentTime — sends the
  exact frame boundary.

Point + review UX
- Video pauses aggressively on scrubber grab (mousedown/pointerdown/
  touchstart) AND on every input, with a 30ms follow-up to beat HLS.js
  race conditions.
- Zoom buttons now scope by data-pcs-zoom / data-rcb-zoom so clicks on
  the review-strip zoom don't clobber the point-strip zoom (root cause
  of the "resets while button still on 20x" bug).
- Point cards now play a preroll/postroll clip at 1× then replay at
  the chosen slow-mo rate, then resume normal playback.
- REPLAY ×N badge shown in the top-left of the video during replays,
  swapping palette when slow-mo kicks in.
- Slow-mo picker (¼× ½× ¾×) in the tab-header — window.slowmoRate is
  the source of truth for both point and review replays.
- Clicking a card hides the player chrome (controls-hidden re-applied
  across 0/10/60/200/500ms to beat pause/seek/play showControls races);
  mousemove over the video brings them back instantly.
- Review-tools slow-mo button removed — the card click IS the trigger.

Coach review specific
- Dual-thumb scrubber on a shared track with a red fill between the
  thumbs (visualises the note's range). Start clamps to ≤ end and
  vice-versa; nudges act on the last-touched thumb.
- Note overlay live-previews as user types and is drag-to-position;
  overlay position persists (position_x/position_y decimal(6,4)).
- Overlay uses container-query units (cqi) so text scales with the
  player width and position stays proportional on any resize.
- Timeline card design (chapter-style time label + subtle card with
  emoji, note, coach name, tools) — nothing else selected.

Sidebar
- "Rounds & points" / "Private notes" section labels removed; only
  the owner-only + Add Round / + Add Note button remains.
- Points that share a timestamp within a round collapse into ONE card
  with a chip per side (equal-width Blue/Red pills), one edit/delete
  pair, and a coloured score line (yellow ROUND N, blue/red score
  badges — background pills with white numerals).
- On mobile the highlights sheet only closes via its own toggle now.
  Backdrop is pointer-events: none so taps pass through to the video.

Mobile capture strip
- Renders below the video on mobile portrait so the paused frame is
  visible while typing. Wider inner padding (10px 20px 14px) so
  content doesn't sit on the edges.
- .pcs-entry uses flex-wrap: nowrap and Action input shrinks to
  fit — the row stays on one line at any width.

Collapsed action menu (video-actions component)
- Every viewport now shows the single  Action dropdown; individual
  desktop-action buttons are hidden by CSS across the board.

SPA navigation fixes
- window.videoId + isOwner now live on window so navigation to a new
  match video via Up Next can update them via reloadMatchVideoState.
- Tabs, event-item clicks, highlights toggle and sidebar-height sync
  re-hydrate on each SPA swap.
- Blade point-time regression: "{{ '@' . $fmtTime(...) }}" instead of
  the misused "@{{ ... }}" escape directive.

Backend
- Point-score recompute (recomputeRoundScores) already sums by
  (timestamp, id) order — works fine with the new decimal columns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-09 02:26:19 +03:00
ghassan
716693a74f Coach reviews: in-player capture strip, draggable overlay, timeline UI
Capture strip
- Twin of the point-capture strip, embedded inside #ytpWrap. Two time slots
  (Start + optional End) with the scrubber driving whichever is "active".
  Editable mm:ss inputs, zoom (1x/5x/20x), inline note + coach name + emoji
  chip picker. Cancel / Save on the right; Delete in edit mode.
- ▶ preview button plays Start → End and auto-pauses at End; click again to
  stop early. Playback uses the live overlay so previewing shows what the
  viewer will see.
- Removed the #reviewModal popup; openAddReviewModal(), setReviewEmoji(),
  saveReview() and the reviewForm submit binding are gone.

Live-preview overlay + drag-to-position
- As the user types, the coach-note overlay updates on the video in real
  time. In capture mode the overlay is grab-able and draggable to any spot
  over the video (mouse + touch), with a red dashed outline + "↕ drag me"
  hint.
- Overlay position is stored as normalized 0..1 CENTER coords of the video
  wrap and applied via `left: X%; top: Y%; transform: translate(-50%,-50%)`
  so the overlay stays at the same relative spot on any resize / fullscreen.
- Font-size, padding and border-radius scale with the player width via CSS
  container queries (`container-type: inline-size` on #ytpWrap + `clamp(...cqi)`),
  so the note grows/shrinks proportionally.
- Draggable overlay lives above the strip (z-index 70 vs 60) so it can be
  dropped anywhere including over the strip.

Persistence (schema change)
- Migration 2026_08_08_000001_add_position_to_coach_reviews: adds nullable
  decimal(6,4) position_x / position_y to coach_reviews.
- CoachReview fillable + casts updated. store/updateReview validate
  position_x / position_y as numeric between 0 and 1 and persist them.
- showCoachNoteOverlay(text, pos) applies the saved position on playback.

Cards: timeline design (Option B from the mockup)
- Vertical spine with red dots on the left; each review is a chapter-style
  time label above a subtle card. Card body: emoji as the leading indicator,
  note text, then coach name + tools (▶ / ✏️ / 🗑).
- ▶ = playReviewSlowmo(id): plays Start → End once at 1×, then loops back
  and plays again at 0.5×, then pauses and hides the overlay. Only rendered
  when the review has an end_time > start_time.
- Card body still clickable for the classic "jump-and-play-once" behaviour.
- Fixes a latent bug where the primary Save button stayed disabled after a
  successful save, silently swallowing the next click. Both the review and
  point capture strips now re-enable the button in their cancel handlers.

Also
- Design mockup file at public/coach-review-mockups.html shows the four
  candidate layouts side by side (kept for future design iterations).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-08 07:07:03 +03:00
ghassan
69f5df163a update the match view 2026-03-12 03:59:52 +03:00