Skip to content

Redesign recording playback UI#208

Merged
fank merged 31 commits intomainfrom
feat/playback-redesign
Feb 13, 2026
Merged

Redesign recording playback UI#208
fank merged 31 commits intomainfrom
feat/playback-redesign

Conversation

@fank
Copy link
Member

@fank fank commented Feb 13, 2026

Summary

  • Complete playback page redesign with glassmorphism UI — new TopBar, BottomBar, SidePanel with Units/Events/Stats/Chat tabs
  • Refactored project structure: dissolved ui/ wrapper, consolidated CSS variables, moved hooks/i18n/styles to top-level
  • Added follow indicator chip with auto-unfollow on map drag, map controls, style switcher, speed selector, timeline scrubber, share button, keyboard hints
  • Wired up i18n translations, time mode dropdown, kill/death counts, and counter display
  • Removed old panel components (LeftPanel, RightPanel, TopPanel, BottomPanel, ToggleBar) and legacy controls

Test plan

  • npx tsc --noEmit — no new type errors in changed files
  • npx vitest run — all 582 tests pass
  • Manual: verify playback page renders with new glassmorphism UI
  • Manual: verify follow indicator appears when clicking a unit, disappears on map drag or X click
  • Manual: verify side panel tabs (Units, Events, Stats) work correctly
  • Manual: verify style switcher, speed selector, and timeline scrubber function

fank added 26 commits February 13, 2026 13:11
Replace the old gray/orange playback UI with a modern dark-navy
glassmorphism design matching the mission selector page.

- New components: TopBar, BottomBar (with custom timeline scrubber and
  speed selector), SidePanel (tabbed: Units/Events/Stats/Chat),
  MapControls, KeyboardHints
- Merge left+right panels into single tabbed SidePanel
- Move layer toggles from Leaflet control into TopBar dropdown,
  including MapLibre-specific layers (map icons, 3D buildings)
- Add deathCount tracking to Unit, keyboard shortcut for events tab
- Delete 15 old panel components and their tests
Kill and death counts were computed once at load time and stored on
Unit objects, causing the UI to show final totals from frame 0.

Add EventManager.getKillDeathCounts(frame) that scans events up to
the current frame, and use it in UnitsTab and StatsTab so counts
update as the recording plays.
Remove top:50px from .leaflet-left that pinned controls near the old
top panel. Use --pb-bottom-height for .leaflet-bottom offset so the
scale ruler sits above the bottom bar, aligned with the side panel.
The early break assumed events were sorted by frame, but the event
array order depends on the source data and isn't guaranteed. Changed
break to continue so all events up to the current frame are counted.
Cover frame boundaries, accumulation, self-kills, vehicle victims,
hit-vs-killed filtering, non-kill events, and out-of-order events.
The default attribution control overlapped the map style switcher
buttons. Pin it just above the bottom bar at reduced opacity.
Add getMapStyles/setMapStyle/getActiveStyleIndex to MapRenderer interface.
Leaflet renderer probes available styles, generates 128×128 preview
thumbnails, and exposes them to MapControls via the renderer API.
Remove old basemap/maplibre-style circular switcher CSS and controls.
Style switching is now handled through the renderer interface and
MapControls component. Remove the unused Leaflet control classes,
their factory functions, and associated tests.
…dcoded colors

Promote mission-selector --ms-* variables to app-wide unprefixed names
(--accent-blue, --text-primary, --font-mono, etc.) and replace ~100
hardcoded hex colors in playback components with variable references.
Delete 12 unused legacy variables, keep --highlight/--bg-modal for
MissionModal/Hint compatibility.
Promote shared dirs (hooks/, i18n/, styles/) to top-level src/ peers.
Colocate all playback components under pages/recording-playback/components/.
Delete the confusing ui/src/ui/ double-nesting entirely.

Fix "Operation not found" false positive caused by engine.loadOperation()
triggering snapshot effects before renderer.init() — the renderer's map
was undefined when useRenderBridge tried to create markers. Solved by
passing an onWorldResolved callback so setWorldConfig (and thus
renderer.init) fires before engine snapshots propagate. Also split the
bare catch block to distinguish API failures from load errors.
Replace the separate /loading route with an overlay inside
RecordingPlayback that shows during actual data loading and
fades out smoothly when done.
The Go parser was dropping messages for generalEvent, endMission,
captured, capturedFlag, and terminalHack events — their string data
fell into the hit/killed parsing path and was lost. The frontend
protobuf decoder also lacked cases for these types, silently
discarding them.

Add comprehensive roundtrip and parser-level tests for all event types.
- Replace lightning bolt (ZapIcon) with horizontal BulletIcon for hit events
- Show "(suicide)" instead of duplicate names when victim === killer
- Hide hit events by default (toggle still available)
- Event click pans to victim without persistent follow
- Add panToEntity() to engine; followEntity() now also pans immediately
- Show "Link copied!" toast below share button for 2s
- Replace hardcoded background colors with var(--bg-panel)
- Global kbd style in base.css replaces duplicates across components
- Redesign AboutModal to match playback design system (blur panel, sections)
- Remove R shortcut (keep only Space + E), update tests
- Show E shortcut badge on Panel button in bottom bar
- Remove floating KeyboardHints overlay
- Use import.meta.env.BASE_URL for download href and logo
Add 35 new translation keys (en, ru, de, cs, it, fr) and wire useI18n
into 10 playback components. Replace native select dropdowns with custom
popups matching the speed selector styling.
Flow date and timeMultiplier from TimeSample through decoders into the
engine's timeConfig. Replace disabled time button with working dropdown
that enables mission and system time modes when data is available.
- Floating chip above bottom bar shows followed unit name with side color dot
- Clicking a followed unit in the list toggles follow off
- Dragging the map auto-unfollows so panning no longer snaps back
@github-actions
Copy link

github-actions bot commented Feb 13, 2026

Coverage Report for ui

Status Category Percentage Covered / Total
🔵 Lines 74.69%
⬇️ -0.68%
2890 / 3869
🔵 Statements 71.82%
⬇️ -2.57%
3592 / 5001
🔵 Functions 71.94%
⬇️ -3.87%
882 / 1226
🔵 Branches 60.12%
⬇️ -1.62%
1407 / 2340
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
ui/src/App.tsx 100%
🟰 ±0%
50%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/main.tsx 0%
🟰 ±0%
0%
🟰 ±0%
0%
🟰 ±0%
0%
🟰 ±0%
8-23
ui/src/config/side-colors.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/data/types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/data/decoders/json-decoder.ts 87.85%
🟰 ±0%
66.89%
⬆️ +0.94%
100%
🟰 ±0%
89.1%
🟰 ±0%
121, 193, 229-275, 280
ui/src/data/decoders/protobuf-decoder.ts 78.66%
⬇️ -3.28%
51.76%
⬇️ -8.84%
100%
🟰 ±0%
76.92%
⬇️ -3.72%
42-46, 48-52, 128-148, 181
ui/src/pages/mission-selector/DetailSidebar.tsx 39.46%
🟰 ±0%
35.18%
🟰 ±0%
48.83%
🟰 ±0%
42.85%
🟰 ±0%
85-92, 146-175
ui/src/pages/mission-selector/MissionRow.tsx 67.44%
🟰 ±0%
30.76%
🟰 ±0%
68.75%
🟰 ±0%
88.09%
🟰 ±0%
58-61, 65-68, 75, 89
ui/src/pages/mission-selector/MissionSelector.tsx 82.06%
🟰 ±0%
73.55%
🟰 ±0%
78.7%
🟰 ±0%
89.68%
🟰 ±0%
74-85, 113, 114, 140-141, 189-191, 212-213, 215-216, 224, 231-234, 332, 333-334, 336-337, 375
ui/src/pages/mission-selector/components.tsx 100%
🟰 ±0%
93.33%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/pages/mission-selector/constants.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/pages/recording-playback/RecordingPlayback.tsx 0% 0% 0% 0% 46-170
ui/src/pages/recording-playback/index.tsx 100% 100% 100% 100%
ui/src/pages/recording-playback/load-operation.ts 0% 0% 0% 0% 26-58
ui/src/pages/recording-playback/useRenderBridge.ts 100% 90% 100% 100%
ui/src/pages/recording-playback/components/AboutModal.tsx 86.59% 46.66% 88.46% 92.3% 26, 35, 41, 73-76, 101
ui/src/pages/recording-playback/components/BottomBar.tsx 60.93% 17.85% 46.15% 65.95% 55-63, 76-80, 158, 163-164, 193, 198-199
ui/src/pages/recording-playback/components/ChatTab.tsx 0% 0% 0% 0% 6-9
ui/src/pages/recording-playback/components/EventsTab.tsx 63.52% 46.55% 66.66% 65.54% 22-24, 35-36, 46-47, 79-88, 218-272
ui/src/pages/recording-playback/components/FollowIndicator.tsx 97.05% 75% 100% 100% 15
ui/src/pages/recording-playback/components/Icons.tsx 80.43% 76.78% 77.35% 88.88% 59-60, 65-66, 93-94, 182-183, 196-197, 204-205
ui/src/pages/recording-playback/components/KeyboardHints.tsx 0% 0% 0% 0% 8-16
ui/src/pages/recording-playback/components/MapControls.tsx 45.83% 18.75% 32.14% 53.84% 21-27, 29, 48-49, 54-55, 72-96
ui/src/pages/recording-playback/components/SidePanel.tsx 81.13% 42.85% 85.71% 90% 25, 48-49
ui/src/pages/recording-playback/components/SpeedSelector.tsx 100% 70% 100% 100%
ui/src/pages/recording-playback/components/StatsTab.tsx 100% 91.66% 100% 100%
ui/src/pages/recording-playback/components/TimelineScrubber.tsx 78.78% 55.55% 70.58% 84.61% 31, 45-48, 53, 57, 93-97
ui/src/pages/recording-playback/components/TopBar.tsx 84.61% 66.66% 82.97% 84.54% 80-81, 94-97, 111-112, 123-131, 141, 201, 249-250
ui/src/pages/recording-playback/components/UnitsTab.tsx 87.26% 75% 85.71% 91.96% 47, 89-96, 125, 151, 201-202, 209-210
ui/src/playback/engine.ts 90.78%
⬆️ +1.26%
80.76%
⬆️ +3.31%
94.28%
⬆️ +3.38%
92.71%
⬆️ +0.25%
43-51, 58, 202, 210, 341, 347-349, 395-396, 419-423, 439
ui/src/playback/event-manager.ts 100%
🟰 ±0%
97.61%
⬆️ +5.31%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/playback/entities/unit.ts 91.66%
⬆️ +13.40%
80%
⬆️ +10.00%
100%
🟰 ±0%
95%
⬆️ +10.79%
53, 69
ui/src/renderers/mock-renderer.ts 100%
🟰 ±0%
100%
🟰 ±0%
67.85%
⬆️ +5.35%
100%
🟰 ±0%
ui/src/renderers/renderer.interface.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/renderers/renderer.types.ts 100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
100%
🟰 ±0%
ui/src/renderers/leaflet/leaflet-controls.ts 100%
⬆️ +71.43%
100%
⬆️ +75.59%
100%
⬆️ +63.34%
100%
⬆️ +68.75%
ui/src/renderers/leaflet/leaflet-renderer.ts 37.08%
⬇️ -3.02%
27.27%
⬇️ -3.84%
23.75%
⬇️ -4.82%
38.31%
⬇️ -3.00%
82-86, 98-110, 193-194, 198, 220, 223-224, 227, 230-419, 500-506, 509-515, 518-524, 529-534, 561, 587, 594-600, 608, 617, 622, 627, 632-633, 648, 659-775, 829, 856-859, 884-910, 931, 1009-1195, 1206-1293
Generated in workflow #52 for commit 99f669a by the Vitest Coverage Report Action

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @fank, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant overhaul of the recording playback user interface, moving to a modern glassmorphism design. It streamlines the project's frontend architecture by reorganizing core UI elements and enhancing user interaction with new, intuitive controls. The changes also include backend improvements for event parsing and robust testing to ensure data integrity during conversion and playback.

Highlights

  • Complete UI Redesign: The recording playback page has been completely redesigned with a modern glassmorphism UI, introducing new TopBar, BottomBar, and a SidePanel with Units, Events, Stats, and Chat tabs.
  • Refactored Project Structure: The ui/ wrapper directory has been dissolved, and common assets like hooks, i18n, and styles have been consolidated to top-level directories for a cleaner project layout.
  • Enhanced Playback Controls: New features include a follow indicator chip with auto-unfollow on map drag, map controls (zoom, style switcher), a speed selector, a timeline scrubber with event markers, a share button, and keyboard hints for common actions.
  • Improved Event Handling and Statistics: Internationalization (i18n) translations have been wired up, a time mode dropdown added, and kill/death counts are now displayed. The event parsing logic in the backend (Go) has been extended to correctly handle various event types, including general events, end mission, captured, and terminal hack events, with comprehensive new tests.
  • Removed Legacy Components: Old panel components (LeftPanel, RightPanel, TopPanel, BottomPanel, ToggleBar) and legacy controls have been removed, streamlining the codebase and UI.
Changelog
  • internal/storage/converter_test.go
    • Added TestConverter_AllEventTypes to verify roundtrip conversion for all event types.
  • internal/storage/parser_test.go
    • Added new test cases for generalEvent, endMission, captured, capturedFlag, terminalHackStarted, terminalHackCanceled, and respawnTickets parsing.
  • internal/storage/parser_v1.go
    • Imported strings package.
    • Implemented parsing logic for generalEvent to extract messages.
    • Implemented parsing logic for endMission to handle [side, message] tuples and plain strings.
    • Implemented parsing logic for captured and capturedFlag events to join array data into a message string.
    • Implemented parsing logic for terminalHackStarted and terminalHackCanceled events to join array data into a message string.
  • ui/src/App.tsx
    • Updated import paths for I18nProvider, CustomizeProvider, and CSS styles from ui/hooks and ui/styles to top-level hooks and styles.
  • ui/src/config/side-colors.ts
    • Added SIDE_COLORS_UI for redesign UI color variables.
    • Added SIDE_BG_COLORS for translucent background variants in the redesign UI.
  • ui/src/data/decoders/json-decoder.ts
    • Updated RawJsonOperation interface to include optional date and timeMultiplier properties in the times array.
    • Updated JsonDecoder to map date and timeMultiplier from raw JSON to the decoded times array.
  • ui/src/data/decoders/protobuf-decoder.ts
    • Updated convertEvent to handle generalEvent messages.
    • Updated convertEvent to parse captured and capturedFlag messages into unitName and objectType.
    • Updated convertEvent to parse terminalHackStarted and terminalHackCanceled messages into unitName.
    • Updated ProtobufDecoder to map date and timeMultiplier from protobuf times to the decoded times array.
  • ui/src/data/types.ts
    • Updated Manifest interface to include optional date and timeMultiplier properties in the times array.
  • ui/src/main.tsx
    • Removed import and route for LoadingTransition component.
    • Updated import path for RecordingPlayback component.
    • Modified navigation logic to directly route to /recording/:id/:name instead of /loading/:id/:name.
  • ui/src/pages/LoadingTransition.module.css
    • Modified .loadingScreen to use position: fixed, z-index: 10000, and transition: opacity.
    • Updated background color variable from --ms-bg-dark to --bg-dark.
    • Removed animation: fadeIn from .loadingScreen and .loadingContent.
    • Updated color and font variables in .loadingTitle, .loadingSubtitle, .loadingBarFill, and .loadingHint from ms- prefixed to new generic variables.
  • ui/src/pages/LoadingTransition.tsx
    • Removed file.
  • ui/src/pages/RecordingPlayback.tsx
    • Removed file.
  • ui/src/pages/mission-selector/DetailSidebar.tsx
    • Updated import path for useI18n from ../../ui/hooks/useLocale to ../../hooks/useLocale.
  • ui/src/pages/mission-selector/MissionRow.tsx
    • Updated import path for useI18n from ../../ui/hooks/useLocale to ../../hooks/useLocale.
    • Updated CSS variable for kill count color from --ms-text-muted and --ms-text-dimmer to --text-muted and --text-dimmer.
  • ui/src/pages/mission-selector/MissionSelector.module.css
    • Updated CSS variables for background, text colors, and fonts from ms- prefixed to new generic variables.
    • Removed searchKbd styling.
  • ui/src/pages/mission-selector/MissionSelector.tsx
    • Updated import paths for useI18n, useCustomize, and LOCALES.
    • Modified handleLaunch to navigate directly to /recording/:id/:name instead of /loading/:id/:name.
    • Updated CSS variables for map button colors from ms- prefixed to new generic variables.
  • ui/src/pages/mission-selector/tests/DetailSidebar.test.tsx
    • Updated import paths for I18nProvider and CustomizeProvider.
  • ui/src/pages/mission-selector/tests/MissionSelector.test.tsx
    • Updated import paths for I18nProvider and CustomizeProvider.
    • Removed import for LoadingTransition.
    • Replaced LoadingTransition component with RecordingStub in test setup.
  • ui/src/pages/mission-selector/components.tsx
    • Updated import path for useI18n.
    • Updated CSS variable for tag badge color from --ms-text-dimmer to --text-dimmer.
  • ui/src/pages/mission-selector/constants.ts
    • Updated CSS variable names for colors from ms- prefixed to new generic variables.
  • ui/src/pages/recording-playback/RecordingPlayback.tsx
    • Added new file for the redesigned playback page, including new UI components like TopBar, SidePanel, BottomBar, MapControls, FollowIndicator, and KeyboardHints.
  • ui/src/pages/recording-playback/components/AboutModal.module.css
    • Added new CSS module for the About Modal component, defining styles for overlay, modal, header, body, sections, and language selector.
  • ui/src/pages/recording-playback/components/AboutModal.tsx
    • Added new component for the About Modal, displaying version information, shortcuts, and a language selector.
  • ui/src/pages/recording-playback/components/BottomBar.module.css
    • Added new CSS module for the BottomBar component, defining styles for timeline scrubber, playback controls, speed selector, and dropdowns.
  • ui/src/pages/recording-playback/components/BottomBar.tsx
    • Added new component for the BottomBar, incorporating timeline scrubber, playback controls, speed selector, and time/name mode dropdowns.
  • ui/src/pages/recording-playback/components/ChatTab.tsx
    • Added new component for the Chat tab within the SidePanel, displaying a 'Chat messages not available' placeholder.
  • ui/src/pages/recording-playback/components/CounterDisplay.module.css
    • Renamed from ui/src/ui/components/CounterDisplay.module.css.
  • ui/src/pages/recording-playback/components/CounterDisplay.tsx
    • Renamed from ui/src/ui/components/CounterDisplay.tsx.
    • Updated import path for useEngine and getCounterStateAtFrame.
  • ui/src/pages/recording-playback/components/CustomizeLogo.module.css
    • Renamed from ui/src/ui/components/CustomizeLogo.module.css.
    • Updated CSS variable for left panel width from --left-panel-width to --pb-panel-width.
  • ui/src/pages/recording-playback/components/CustomizeLogo.tsx
    • Renamed from ui/src/ui/components/CustomizeLogo.tsx.
    • Updated import path for useCustomize.
  • ui/src/pages/recording-playback/components/EventsTab.tsx
    • Added new component for the Events tab within the SidePanel, including event filtering and display logic.
  • ui/src/pages/recording-playback/components/FollowIndicator.module.css
    • Added new CSS module for the FollowIndicator component.
  • ui/src/pages/recording-playback/components/FollowIndicator.tsx
    • Added new component for the FollowIndicator, displaying the name and side of the followed entity.
  • ui/src/pages/recording-playback/components/Hint.module.css
    • Renamed from ui/src/ui/components/Hint.module.css.
  • ui/src/pages/recording-playback/components/Hint.tsx
    • Renamed from ui/src/ui/components/Hint.tsx.
  • ui/src/pages/recording-playback/components/Icons.tsx
    • Added new file containing various SVG icons used throughout the redesigned UI.
  • ui/src/pages/recording-playback/components/KeyboardHints.tsx
    • Added new component for displaying keyboard shortcut hints.
  • ui/src/pages/recording-playback/components/MapContainer.tsx
    • Renamed from ui/src/ui/components/MapContainer.tsx.
    • Updated import paths for MapRenderer and WorldConfig.
  • ui/src/pages/recording-playback/components/MapControls.module.css
    • Added new CSS module for the MapControls component, defining styles for zoom controls and style switcher.
  • ui/src/pages/recording-playback/components/MapControls.tsx
    • Added new component for map controls, including zoom buttons and a map style switcher with previews.
  • ui/src/pages/recording-playback/components/MissionModal.module.css
    • Renamed from ui/src/ui/components/MissionModal.module.css.
  • ui/src/pages/recording-playback/components/SidePanel.module.css
    • Added new CSS module for the SidePanel component, defining styles for tabs, groups, unit rows, event filters, event rows, and stats display.
  • ui/src/pages/recording-playback/components/SidePanel.tsx
    • Added new component for the SidePanel, managing tabs for Units, Events, and Stats.
  • ui/src/pages/recording-playback/components/SpeedSelector.tsx
    • Added new component for the Speed Selector dropdown in the BottomBar.
  • ui/src/pages/recording-playback/components/StatsTab.tsx
    • Added new component for the Stats tab within the SidePanel, displaying force summary and leaderboard.
  • ui/src/pages/recording-playback/components/TimelineScrubber.tsx
    • Added new component for the Timeline Scrubber, allowing seeking and displaying event markers.
  • ui/src/pages/recording-playback/components/TopBar.module.css
    • Added new CSS module for the TopBar component, defining styles for mission info, force indicators, action buttons, layer dropdown, and copied toast.
  • ui/src/pages/recording-playback/components/TopBar.tsx
    • Added new component for the TopBar, displaying mission information, force statistics, layer controls, download, share, and info buttons.
  • ui/src/pages/recording-playback/components/UnitsTab.tsx
    • Added new component for the Units tab within the SidePanel, displaying units grouped by side and squad.
  • ui/src/pages/recording-playback/index.tsx
    • Added new index file for recording-playback page components.
  • ui/src/pages/recording-playback/load-operation.ts
    • Added new utility function loadOperation to centralize the logic for loading operation data, including handling different storage formats (protobuf/JSON) and chunk management.
  • ui/src/pages/recording-playback/shortcuts.ts
    • Renamed from ui/src/ui/shortcuts.ts.
    • Updated import path for PlaybackEngine.
    • Removed rightPanelVisible signal and added activePanelTab signal.
    • Simplified shortcut logic to only toggle the left panel with 'e' key.
  • ui/src/pages/recording-playback/useRenderBridge.ts
    • Added new SolidJS hook useRenderBridge to synchronize engine state with renderer, manage entity markers, update briefing markers, and handle map drag events for unfollowing entities.
  • ui/src/playback/tests/event-manager.test.ts
    • Added a new test suite for getKillDeathCounts to verify accurate calculation of kills and deaths up to a specific frame, handling self-kills, vehicle victims, and event types.
  • ui/src/playback/engine.ts
    • Added timeConfig getter to provide structured time configuration.
    • Added panToEntity method to move the camera to a specific entity without following.
    • Modified followEntity to automatically pan the camera to the followed entity.
  • ui/src/playback/entities/unit.ts
    • Added deathCount property to the Unit class.
  • ui/src/playback/event-manager.ts
    • Modified getActiveEvents to ensure events are sorted ascending by frameNum.
    • Added deathCount increment logic for victims in resolveReferences.
    • Added getKillDeathCounts method to compute per-unit kill and death counts up to a given frame.
  • ui/src/renderers/leaflet/tests/leaflet-controls.test.ts
    • Removed tests for createLayerControl, createBasemapControl, and createMaplibreStyleControl.
  • ui/src/renderers/leaflet/leaflet-controls.ts
    • Removed createLayerControl function.
    • Removed BasemapControl class and createBasemapControl function.
    • Removed MaplibreStyleControl class and createMaplibreStyleControl function.
  • ui/src/renderers/leaflet/leaflet-renderer.ts
    • Removed imports for createBasemapControl and createMaplibreStyleControl.
    • Added internal state variables _mapStyles, _activeStyleIndex, and _styleSwitchFn for map style management.
    • Removed attributionControl: true from Leaflet map options.
    • Refactored MapLibre style handling to populate _mapStyles and use an internal _styleSwitchFn for UI integration.
    • Implemented getMapStyles, getActiveStyleIndex, and setMapStyle methods.
    • Added private method _renderStylePreview for generating MapLibre style thumbnails.
    • Updated addOverlayControl to remove Leaflet's default layer control and initialize MapLibre toggle layers for icons and 3D buildings.
  • ui/src/renderers/mock-renderer.ts
    • Added mock implementations for getMapStyles, getActiveStyleIndex, setMapStyle, and setNameDisplayMode.
  • ui/src/renderers/renderer.interface.ts
    • Added MapStyleInfo import.
    • Added getMapStyles, getActiveStyleIndex, and setMapStyle methods to the MapRenderer interface.
  • ui/src/renderers/renderer.types.ts
    • Extended RenderLayer type to include mapIcons and buildings3D.
    • Defined MapStyleInfo interface for map style metadata.
  • ui/src/styles/tests/styles.test.ts
    • Renamed from ui/src/ui/styles/__tests__/styles.test.ts.
    • Updated componentsDir path to reflect new UI structure.
    • Updated CSS variable checks to match new naming conventions (e.g., ms- prefixes removed).
    • Removed tests for old panel-specific CSS variables.
    • Added test for .leaflet-control-scale-line in leaflet.css.
    • Updated list of CSS module files to reflect new component structure.
  • ui/src/styles/base.css
    • Added new base CSS file, including global resets, map container styles, new keyframe animations (fadeIn, slideInLeft, slideInRight), custom scrollbar styles, and keyboard shortcut badge styles.
  • ui/src/styles/entities.css
    • Renamed from ui/src/ui/styles/entities.css.
  • ui/src/styles/global.css
    • Renamed from ui/src/ui/styles/global.css.
  • ui/src/styles/leaflet.css
    • Added new Leaflet-specific CSS overrides, adjusting positioning of controls, popup styles, and scale ruler theming.
  • ui/src/styles/responsive.css
    • Renamed from ui/src/ui/styles/responsive.css.
    • Removed top: 50px from .leaflet-left media query rule.
  • ui/src/styles/variables.css
    • Added new CSS variables file, defining a new accent palette, text scale, backgrounds, fonts, and playback layout dimensions (--pb-top-height, --pb-bottom-height, --pb-panel-width).
    • Removed old ms- prefixed variables and legacy panel dimension variables.
Activity
  • The pull request includes a complete UI redesign, indicating significant frontend development.
  • Automated checks for TypeScript compilation (npx tsc --noEmit) and unit tests (npx vitest run) have passed, ensuring code quality and preventing regressions.
  • Manual testing is planned to verify the new glassmorphism UI, follow indicator functionality, side panel tabs, and various playback controls.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a major and impressive redesign of the recording playback UI, along with a significant refactoring of the frontend project structure. The new UI looks modern, and the code organization is much cleaner with the consolidation of hooks, styles, and i18n resources. The backend changes to support more event types are also well-implemented and come with thorough tests.

I have one minor suggestion to reduce some code duplication in the Go parser, but overall this is an excellent set of changes that greatly improves the user experience and maintainability of the codebase.

Add 60 new tests covering FollowIndicator, UnitsTab, EventsTab,
StatsTab, SidePanel, TopBar, BottomBar, MapControls, and
useRenderBridge. Shared test helpers provide engine/renderer setup
and entity/event factories. Total test count: 582 → 642.
fank added 3 commits February 13, 2026 19:00
…TimelineScrubber

Covers remaining untested playback components: auto-dismiss hints,
counter state display, speed dropdown, about modal open/close and
versions, timeline scrubber progress and event markers. 642 → 670 tests.
@fank fank force-pushed the feat/playback-redesign branch from 479810d to 821339d Compare February 13, 2026 18:44
Two issues caused inaccurate Go coverage reporting:

1. Multiple test binaries each write coverage entries for the same source
   file when using -coverpkg. fgrosse/go-coverage-report doesn't merge
   duplicates, counting each entry as a separate statement. This inflated
   statement counts ~4x and deflated percentages.

2. actions/setup-go restores the Go build/test cache across CI runs.
   When a -coverpkg target file changes but a test package doesn't import
   it (e.g. internal/maptool doesn't import internal/storage), the cached
   test binary retains stale coverage instrumentation with old line numbers.
   These "ghost blocks" appear as uncovered phantom statements.
   Verified: ghost blocks in the PR profile are a 100% exact match with
   the main branch's coverage blocks (161 blocks, lines 4-486 vs current
   file lines 6-526).

Fix: add -count=1 to disable test result caching (forces fresh coverage
data), and deduplicate the profile by merging entries per block (takes
max count), eliminating both duplicate entries and ghost blocks.
@fank fank force-pushed the feat/playback-redesign branch from 821339d to 99f669a Compare February 13, 2026 18:45
@github-actions
Copy link

Merging this branch will increase overall coverage

Impacted Packages Coverage Δ 🤖
github.com/OCAP2/web/internal/storage 93.06% (+42.84%) 🌟

Coverage by file

Changed files (no unit tests)

Changed File Coverage Δ Total Covered Missed 🤖
github.com/OCAP2/web/internal/storage/parser_v1.go 100.00% (+54.20%) 231 (-793) 231 (-238) 0 (-555) 🌟

Please note that the "Total", "Covered", and "Missed" counts above refer to code statements instead of lines of code. The value in brackets refers to the test coverage of that file in the old version of the code.

Changed unit test files

  • github.com/OCAP2/web/internal/storage/converter_test.go
  • github.com/OCAP2/web/internal/storage/parser_test.go

@fank fank merged commit ae45452 into main Feb 13, 2026
3 checks passed
@fank fank deleted the feat/playback-redesign branch February 13, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant