feat: Implement scrolling camera with layout-aware filtering

- Rename VERTICAL camera mode to FEED (rapid single-item view)
- Add SCROLL camera mode with float accumulation for smooth movie-credits style scrolling
- Add estimate_block_height() for cheap layout calculation without full rendering
- Replace ViewportFilterStage with layout-aware filtering that tracks camera position
- Add render caching to FontStage to avoid re-rendering items
- Fix CameraStage to use global canvas height for scrolling bounds
- Add horizontal padding in Camera.apply() to prevent ghosting
- Add get_dimensions() to MultiDisplay for proper viewport sizing
- Fix PygameDisplay to auto-detect viewport from window size
- Update presets to use scroll camera with appropriate speeds
This commit is contained in:
2026-03-17 00:21:18 -07:00
parent 4c97cfe6aa
commit 57de835ae0
12 changed files with 303 additions and 66 deletions

View File

@@ -75,8 +75,8 @@ class TestViewportFilterPerformance:
With 1438 items and 24-line viewport:
- Without filter: FontStage renders all 1438 items
- With filter: FontStage renders ~5 items
- Expected improvement: 1438 / 5288x
- With filter: FontStage renders ~3 items (layout-based)
- Expected improvement: 1438 / 3479x
"""
test_items = [
SourceItem(f"Headline {i}", "source", str(i)) for i in range(1438)
@@ -89,10 +89,10 @@ class TestViewportFilterPerformance:
filtered = stage.process(test_items, ctx)
improvement_factor = len(test_items) / len(filtered)
# Verify we get expected 288x improvement
assert 250 < improvement_factor < 300
# Verify filtered count is reasonable
assert 4 <= len(filtered) <= 6
# Verify we get expected ~479x improvement (better than old ~288x)
assert 400 < improvement_factor < 600
# Verify filtered count is reasonable (layout-based is more precise)
assert 2 <= len(filtered) <= 5
class TestPipelinePerformanceWithRealData: