feat(core): add Camera abstraction for viewport scrolling

- Add Camera class with modes: vertical, horizontal, omni, floating
- Refactor scroll.py and demo to use Camera abstraction
- Add vis_offset for horizontal scrolling support
- Add camera_x to EffectContext for effects
- Add pygame window resize handling
- Add HUD effect plugin for demo mode
- Add --demo flag to run demo mode
- Add tests for Camera and vis_offset
This commit is contained in:
2026-03-16 01:46:21 -07:00
parent e1408dcf16
commit 9b139a40f7
10 changed files with 343 additions and 37 deletions

View File

@@ -6,6 +6,7 @@ from engine.effects.legacy import (
glitch_bar,
next_headline,
noise,
vis_offset,
vis_trunc,
)
from engine.effects.performance import PerformanceMonitor, get_monitor, set_monitor
@@ -45,4 +46,5 @@ __all__ = [
"noise",
"next_headline",
"vis_trunc",
"vis_offset",
]

View File

@@ -82,6 +82,37 @@ def vis_trunc(s, w):
return "".join(result)
def vis_offset(s, offset):
"""Offset string by skipping first offset visual characters, skipping ANSI escape codes."""
if offset <= 0:
return s
result = []
vw = 0
i = 0
skipping = True
while i < len(s):
if s[i] == "\033" and i + 1 < len(s) and s[i + 1] == "[":
j = i + 2
while j < len(s) and not s[j].isalpha():
j += 1
if skipping:
i = j + 1
continue
result.append(s[i : j + 1])
i = j + 1
else:
if skipping:
if vw >= offset:
skipping = False
result.append(s[i])
vw += 1
i += 1
else:
result.append(s[i])
i += 1
return "".join(result)
def next_headline(pool, items, seen):
"""Pull the next unique headline from pool, refilling as needed."""
while True:

View File

@@ -29,10 +29,11 @@ class EffectContext:
terminal_height: int
scroll_cam: int
ticker_height: int
mic_excess: float
grad_offset: float
frame_number: int
has_message: bool
camera_x: int = 0
mic_excess: float = 0.0
grad_offset: float = 0.0
frame_number: int = 0
has_message: bool = False
items: list = field(default_factory=list)