Compare commits
6 Commits
feat/ntfy-
...
7274f57bbb
| Author | SHA1 | Date | |
|---|---|---|---|
| 7274f57bbb | |||
| c857d7bd81 | |||
| 6a5a73fd88 | |||
| 5474c58ce0 | |||
| 571da4fa47 | |||
| 6d7ab770cd |
46
mainline.py
46
mainline.py
@@ -67,9 +67,16 @@ MESSAGE_DISPLAY_SECS = 30 # how long a message holds the screen
|
||||
POETRY_SOURCES = {
|
||||
"Whitman": "https://www.gutenberg.org/cache/epub/1322/pg1322.txt",
|
||||
"Dickinson": "https://www.gutenberg.org/cache/epub/12242/pg12242.txt",
|
||||
"Thoreau": "https://www.gutenberg.org/cache/epub/205/pg205.txt",
|
||||
"Emerson": "https://www.gutenberg.org/cache/epub/2944/pg2944.txt",
|
||||
"Whitman II": "https://www.gutenberg.org/cache/epub/8388/pg8388.txt",
|
||||
"Rilke": "https://www.gutenberg.org/cache/epub/38594/pg38594.txt",
|
||||
"Pound": "https://www.gutenberg.org/cache/epub/41162/pg41162.txt",
|
||||
"Pound II": "https://www.gutenberg.org/cache/epub/51992/pg51992.txt",
|
||||
"Eliot": "https://www.gutenberg.org/cache/epub/1567/pg1567.txt",
|
||||
"Yeats": "https://www.gutenberg.org/cache/epub/38877/pg38877.txt",
|
||||
"Masters": "https://www.gutenberg.org/cache/epub/1280/pg1280.txt",
|
||||
"Baudelaire": "https://www.gutenberg.org/cache/epub/36098/pg36098.txt",
|
||||
"Crane": "https://www.gutenberg.org/cache/epub/40786/pg40786.txt",
|
||||
"Poe": "https://www.gutenberg.org/cache/epub/10031/pg10031.txt",
|
||||
}
|
||||
|
||||
# ─── ANSI ─────────────────────────────────────────────────
|
||||
@@ -141,6 +148,7 @@ _FONT_PATH = "/Users/genejohnson/Documents/CS Bishop Drawn/CSBishopDrawn-Italic.
|
||||
_FONT_OBJ = None
|
||||
_FONT_SZ = 60
|
||||
_RENDER_H = 8 # terminal rows per rendered text line
|
||||
_SSAA = 4 # super-sampling factor: render at _SSAA× then downsample
|
||||
|
||||
# Non-Latin scripts → macOS system fonts
|
||||
_SCRIPT_FONTS = {
|
||||
@@ -495,9 +503,10 @@ def _save_cache(items):
|
||||
|
||||
|
||||
# ─── STREAM ───────────────────────────────────────────────
|
||||
_SCROLL_DUR = 3.75 # seconds per headline
|
||||
_FRAME_DT = 0.05 # 50ms base frame rate (20 FPS)
|
||||
FIREHOSE_H = 12 # firehose zone height (terminal rows)
|
||||
_SCROLL_DUR = 5.625 # seconds per headline (2/3 original speed)
|
||||
_FRAME_DT = 0.05 # 50ms base frame rate (20 FPS)
|
||||
FIREHOSE_H = 12 # firehose zone height (terminal rows)
|
||||
GRAD_SPEED = 0.08 # gradient traversal speed (cycles/sec, ~12s full sweep)
|
||||
_mic_db = -99.0 # current mic level, written by background thread
|
||||
_mic_stream = None
|
||||
|
||||
@@ -571,8 +580,11 @@ def _render_line(text, font=None):
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text((-bbox[0] + pad, -bbox[1] + pad), text, fill=255, font=font)
|
||||
pix_h = _RENDER_H * 2
|
||||
scale = pix_h / max(img_h, 1)
|
||||
new_w = max(1, int(img_w * scale))
|
||||
hi_h = pix_h * _SSAA
|
||||
scale = hi_h / max(img_h, 1)
|
||||
new_w_hi = max(1, int(img_w * scale))
|
||||
img = img.resize((new_w_hi, hi_h), Image.Resampling.LANCZOS)
|
||||
new_w = max(1, int(new_w_hi / _SSAA))
|
||||
img = img.resize((new_w, pix_h), Image.Resampling.LANCZOS)
|
||||
data = img.tobytes()
|
||||
thr = 80
|
||||
@@ -629,8 +641,8 @@ def _big_wrap(text, max_w, font=None):
|
||||
return out
|
||||
|
||||
|
||||
def _lr_gradient(rows):
|
||||
"""Color each non-space block character with a left-to-right gradient."""
|
||||
def _lr_gradient(rows, offset=0.0):
|
||||
"""Color each non-space block character with a shifting left-to-right gradient."""
|
||||
n = len(_GRAD_COLS)
|
||||
max_x = max((len(r.rstrip()) for r in rows if r.strip()), default=1)
|
||||
out = []
|
||||
@@ -643,7 +655,8 @@ def _lr_gradient(rows):
|
||||
if ch == ' ':
|
||||
buf.append(' ')
|
||||
else:
|
||||
idx = min(round(x / max(max_x - 1, 1) * (n - 1)), n - 1)
|
||||
shifted = (x / max(max_x - 1, 1) + offset) % 1.0
|
||||
idx = min(round(shifted * (n - 1)), n - 1)
|
||||
buf.append(f"{_GRAD_COLS[idx]}{ch}\033[0m")
|
||||
out.append("".join(buf))
|
||||
return out
|
||||
@@ -723,7 +736,6 @@ def _make_block(title, src, ts, w):
|
||||
("\u201d",'"'), ("\u2013","-"), ("\u2014","-")]:
|
||||
title_up = title_up.replace(old, new)
|
||||
big_rows = _big_wrap(title_up, w - 4, lang_font)
|
||||
big_rows = _lr_gradient(big_rows)
|
||||
hc = random.choice([
|
||||
"\033[38;5;46m", # matrix green
|
||||
"\033[38;5;34m", # dark green
|
||||
@@ -854,10 +866,10 @@ def stream(items):
|
||||
cache_key = (display_text, w)
|
||||
if _msg_cache[0] != cache_key:
|
||||
msg_rows = _big_wrap(display_text, w - 4)
|
||||
msg_rows = _lr_gradient(msg_rows)
|
||||
_msg_cache = (cache_key, msg_rows)
|
||||
else:
|
||||
msg_rows = _msg_cache[1]
|
||||
msg_rows = _lr_gradient(msg_rows, (time.monotonic() * GRAD_SPEED) % 1.0)
|
||||
# Center vertically in scroll zone
|
||||
total_h = len(msg_rows) + 4 # +4 for border + meta + padding
|
||||
y_off = max(0, (sh - total_h) // 2)
|
||||
@@ -926,6 +938,7 @@ def stream(items):
|
||||
# Draw scroll zone
|
||||
top_zone = max(1, int(sh * 0.25))
|
||||
bot_zone = max(1, int(sh * 0.10))
|
||||
grad_offset = (time.monotonic() * GRAD_SPEED) % 1.0
|
||||
buf = []
|
||||
for r in range(sh):
|
||||
cy = cam + r
|
||||
@@ -936,13 +949,18 @@ def stream(items):
|
||||
for content, hc, by, midx in active:
|
||||
cr = cy - by
|
||||
if 0 <= cr < len(content):
|
||||
ln = _vis_trunc(content[cr], w)
|
||||
raw = content[cr]
|
||||
if cr != midx:
|
||||
colored = _lr_gradient([raw], grad_offset)[0]
|
||||
else:
|
||||
colored = raw
|
||||
ln = _vis_trunc(colored, w)
|
||||
if row_fade < 1.0:
|
||||
ln = _fade_line(ln, row_fade)
|
||||
if cr == midx:
|
||||
buf.append(f"\033[{r+1};1H{W_COOL}{ln}{RST}\033[K")
|
||||
elif ln.strip():
|
||||
buf.append(f"\033[{r+1};1H{hc}{ln}{RST}\033[K")
|
||||
buf.append(f"\033[{r+1};1H{ln}{RST}\033[K")
|
||||
else:
|
||||
buf.append(f"\033[{r+1};1H\033[K")
|
||||
drawn = True
|
||||
|
||||
Reference in New Issue
Block a user