Add body-camera timeline to the shift review
Full build / Import + headless tests (push) Successful in 30s
Full build / Full desktop build + optional release (push) Failing after 3m38s

- New src/game/ui/event_timeline.gd flattens every recorded incident event
  (ADR-0005) into one time-ordered list and shows time, person, and a one-line
  summary. Step with Left/Right or the buttons; Esc returns to the review. No live
  3D replay in this first version.
- Shift review gains a "Body camera timeline" button that hands the review to the
  timeline; the review dim is hidden while it is open (stacked overlays made the
  screen nearly black) and restored on close.
- ShiftCoordinator records started_at_ms so the review can stamp events as mm:ss.
- 8 new string keys for the timeline UI and the review button.

Tests/docs
- Headless suite 113 -> 120 (test_event_timeline.gd), new smoke_timeline.gd that
  opens the timeline from the review, steps through every event, and closes back.
- README, TODO section moved to DONE, MEMORY notes. Version 0.2.6.
This commit is contained in:
zwitschi committed 2026-10-31 21:02:25 +01:00
1 parent 921bab796e
commit 1b976bf351
14 files changed
+614 -71

No files matched your search

+10
View File
@@ -25,6 +25,7 @@ class ScreenDesignsTests(unittest.TestCase):
"screenshot refs must be unique")
for screen in screen_designs.SCREENS:
self.assertTrue(screen["prompt"].strip())
self.assertIn(screen["kind"], ("scene", "ui"))
self.assertTrue(screen["regions"])
for region in screen["regions"]:
x0, y0, x1, y1, label = region
@@ -42,6 +43,15 @@ class ScreenDesignsTests(unittest.TestCase):
self.assertEqual(image.size,
(screen_designs.WIDTH, screen_designs.HEIGHT))
def test_compose_prompt_appends_kind_specific_style(self):
scene = {"kind": "scene", "prompt": "a street"}
ui = {"kind": "ui", "prompt": "a panel"}
self.assertIn(screen_designs.SCENE_STYLE,
screen_designs._compose_prompt(scene))
self.assertIn(screen_designs.UI_STYLE,
screen_designs._compose_prompt(ui))
self.assertIn("16:9", screen_designs._compose_prompt(scene))
def test_mae_is_zero_for_identical_images(self):
path = self.root / "identical.png"
Image.new("RGB", (1280, 720), (40, 80, 120)).save(path)