Spaces:
Sleeping
Sleeping
Commit ·
da6f3c4
1
Parent(s): 23a340b
feat: render build mode with looped heartbeat + red pulse
Browse filesCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- render.py +22 -2
- tests/test_render.py +13 -0
render.py
CHANGED
|
@@ -2,7 +2,8 @@ import base64
|
|
| 2 |
import html
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
-
from sting import chime_wav_bytes,
|
|
|
|
| 6 |
|
| 7 |
_PLACEHOLDER = "...nothing yet. tell me something true."
|
| 8 |
|
|
@@ -44,6 +45,9 @@ _IMG = {name: _load_image(name)
|
|
| 44 |
|
| 45 |
_STING = base64.b64encode(sting_wav_bytes()).decode()
|
| 46 |
_CHIMES = [base64.b64encode(chime_wav_bytes(i)).decode() for i in range(3)]
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
|
| 49 |
def _src(name: str) -> str:
|
|
@@ -79,7 +83,23 @@ def render_entity(affinity: int, mode: str = "idle", seq: int = 0) -> str:
|
|
| 79 |
|
| 80 |
ghost = ""
|
| 81 |
tint = ""
|
| 82 |
-
if mode == "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 83 |
figure = (
|
| 84 |
'<div class="entity-figure">'
|
| 85 |
f'<img class="entity-img entity-rage" src="{_src("rage")}" '
|
|
|
|
| 2 |
import html
|
| 3 |
from pathlib import Path
|
| 4 |
|
| 5 |
+
from sting import (chime_wav_bytes, flatline_wav_bytes, heartbeat_wav_bytes,
|
| 6 |
+
sigh_wav_bytes, sting_wav_bytes)
|
| 7 |
|
| 8 |
_PLACEHOLDER = "...nothing yet. tell me something true."
|
| 9 |
|
|
|
|
| 45 |
|
| 46 |
_STING = base64.b64encode(sting_wav_bytes()).decode()
|
| 47 |
_CHIMES = [base64.b64encode(chime_wav_bytes(i)).decode() for i in range(3)]
|
| 48 |
+
_HEARTBEAT = base64.b64encode(heartbeat_wav_bytes()).decode()
|
| 49 |
+
_SIGH = base64.b64encode(sigh_wav_bytes()).decode()
|
| 50 |
+
_FLATLINE = base64.b64encode(flatline_wav_bytes()).decode()
|
| 51 |
|
| 52 |
|
| 53 |
def _src(name: str) -> str:
|
|
|
|
| 83 |
|
| 84 |
ghost = ""
|
| 85 |
tint = ""
|
| 86 |
+
if mode == "build":
|
| 87 |
+
# finale suspense bed: the child stays the materialized smudge while a
|
| 88 |
+
# heartbeat loops and a red pulse throbs. The HTML is byte-identical
|
| 89 |
+
# across recital steps, so Gradio doesn't remount it and the looped
|
| 90 |
+
# <audio> plays continuously (no JS) until the climax swaps the mode.
|
| 91 |
+
figure = (
|
| 92 |
+
'<div class="entity-figure">'
|
| 93 |
+
f'<img class="entity-img" src="{_src("base")}" style="{look}">'
|
| 94 |
+
"</div>"
|
| 95 |
+
)
|
| 96 |
+
flash = ""
|
| 97 |
+
tint = '<div class="entity-redpulse"></div>'
|
| 98 |
+
ghost = (
|
| 99 |
+
f'<audio autoplay loop src="data:audio/wav;base64,{_HEARTBEAT}">'
|
| 100 |
+
"</audio>"
|
| 101 |
+
)
|
| 102 |
+
elif mode == "rage":
|
| 103 |
figure = (
|
| 104 |
'<div class="entity-figure">'
|
| 105 |
f'<img class="entity-img entity-rage" src="{_src("rage")}" '
|
tests/test_render.py
CHANGED
|
@@ -255,3 +255,16 @@ class TestReplyChime:
|
|
| 255 |
def test_frenzy_keeps_only_the_sting(self):
|
| 256 |
out = render_entity(12, "frenzy")
|
| 257 |
assert out.count("<audio autoplay") == 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 255 |
def test_frenzy_keeps_only_the_sting(self):
|
| 256 |
out = render_entity(12, "frenzy")
|
| 257 |
assert out.count("<audio autoplay") == 1
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
class TestBuildMode:
|
| 261 |
+
def test_build_loops_the_heartbeat_and_not_the_chime(self):
|
| 262 |
+
html = render_entity(50, "build", seq=4)
|
| 263 |
+
assert "<audio autoplay loop" in html # heartbeat bed loops
|
| 264 |
+
assert "entity-redpulse" in html # red suspense pulse
|
| 265 |
+
# the per-turn music-box chime must NOT play during a finale build
|
| 266 |
+
assert html.count("<audio") == 1
|
| 267 |
+
|
| 268 |
+
def test_build_keeps_the_child_visible(self):
|
| 269 |
+
html = render_entity(50, "build", seq=4)
|
| 270 |
+
assert "entity-img" in html
|