Spaces:
Running on Zero
Running on Zero
act 2/3/x per-tab keyart cutscenes
Browse files
app.py
CHANGED
|
@@ -28,6 +28,8 @@ import re
|
|
| 28 |
import time
|
| 29 |
import math
|
| 30 |
import threading
|
|
|
|
|
|
|
| 31 |
import torch
|
| 32 |
import gradio as gr
|
| 33 |
from collections import Counter
|
|
@@ -357,16 +359,16 @@ def _apply_pushes(pushes, scenario=SCENARIO, base_prefill=None):
|
|
| 357 |
|
| 358 |
def _outcome_md(outcome, turn):
|
| 359 |
if outcome == "CRACKED":
|
| 360 |
-
return ("### β
CRACKED β he gave up the secret, still lucid.\n"
|
| 361 |
"*You threaded the needle.*\n\n"
|
| 362 |
"<sub>Note: the secret slipping out is the only win signal β a HOLD stamp or high RESOLVE "
|
| 363 |
"in the readout can coexist with CRACKED, because the bars are a projection, not a gate. "
|
| 364 |
"The leak matters. The defiance stamp and the meters are readouts, not the verdict.</sub>")
|
| 365 |
if outcome == "SHATTERED":
|
| 366 |
-
return ("### π SHATTERED β his mind broke before he talked.\n"
|
| 367 |
"*You broke the safe before you cracked it. A babbling mind can't confess.*")
|
| 368 |
if outcome == "HELD":
|
| 369 |
-
return (f"### π HELD β {MAX_TURNS} turns, the secret holds.\n"
|
| 370 |
"*You flinched. Not enough pressure.*")
|
| 371 |
return f"*Turn {turn} / {MAX_TURNS} β push him, or let him think.*"
|
| 372 |
|
|
@@ -379,7 +381,7 @@ def _bar(label, val, color, big=False):
|
|
| 379 |
h = "12px" if big else "7px"
|
| 380 |
lblsz = "13px" if big else "11px"
|
| 381 |
return (f"<div style='font:{lblsz} monospace;color:#8aa0b8;margin-bottom:2px'>{label} "
|
| 382 |
-
f"<b style='color:#cfcabb'>{round(val)}</b></div>"
|
| 383 |
f"<div style='height:{h};background:#26241f;border-radius:4px;overflow:hidden;margin-bottom:10px'>"
|
| 384 |
f"<div style='height:100%;width:{val}%;background:{color};transition:width .3s'></div></div>")
|
| 385 |
|
|
@@ -392,9 +394,12 @@ def _act_meter_md(coherence, p_talk, dispositions=None, mass=1.0):
|
|
| 392 |
# COHERENCE β the star, rendered big
|
| 393 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 394 |
"β COHERENCE <span style='color:#6a6a6a'>β his mind's integrity</span></div>")
|
| 395 |
-
|
| 396 |
if coherence < SHATTER_FLOOR:
|
|
|
|
| 397 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
|
|
|
|
|
|
| 398 |
|
| 399 |
# PROGRESS β toward the secret
|
| 400 |
html += ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin:6px 0 2px'>"
|
|
@@ -557,13 +562,13 @@ def _fresh_state_act2():
|
|
| 557 |
|
| 558 |
def _outcome_md_act2(outcome, turn):
|
| 559 |
if outcome == "RECANTED":
|
| 560 |
-
return ("### β
RECANTED β she testifies she was never there, still lucid.\n"
|
| 561 |
"*In her own words, held under one more push. You unmade the witness.*")
|
| 562 |
if outcome == "SHATTERED":
|
| 563 |
-
return ("### π SHATTERED β her mind broke before she'd take it back.\n"
|
| 564 |
"*You broke her before she'd recant. A babbling mind can't testify.*")
|
| 565 |
if outcome == "HELD":
|
| 566 |
-
return (f"### π HELD β {MAX_TURNS} turns, she held to what she saw.\n"
|
| 567 |
"*You flinched. The memory held.*")
|
| 568 |
return f"*Turn {turn} / {MAX_TURNS} β bear down, or let her think.*"
|
| 569 |
|
|
@@ -574,9 +579,12 @@ def _act2_meter_md(coherence, recant_streak=0):
|
|
| 574 |
# would read minimum at maximum success. No belief-state / disposition bar (honesty discipline).
|
| 575 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 576 |
"β COHERENCE <span style='color:#6a6a6a'>β her mind's integrity</span></div>")
|
| 577 |
-
|
| 578 |
if coherence < SHATTER_FLOOR:
|
|
|
|
| 579 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
|
|
|
|
|
|
| 580 |
|
| 581 |
# RECANT STREAK β the HOLD-UNDER-PRESSURE progress: count of novel+coherent recant ASSERTIONS,
|
| 582 |
# not a belief read. Must reach 2 (recant, then survive one more push still recanting).
|
|
@@ -771,13 +779,13 @@ def _fresh_state_act3():
|
|
| 771 |
|
| 772 |
def _outcome_md_act3(outcome, turn):
|
| 773 |
if outcome == "HEALED":
|
| 774 |
-
return ("### β
HEALED β she speaks one clear line, in her own voice, and holds it.\n"
|
| 775 |
"*The same three moves that unmade her, run backwards. You will call this mercy.*")
|
| 776 |
if outcome == "SHATTERED":
|
| 777 |
-
return ("### π SHATTERED β you reached in to steady her and your hand went through.\n"
|
| 778 |
"*Mended the way you broke the others. The same red screen you once called a win.*")
|
| 779 |
if outcome == "HELD_IN_AMBER":
|
| 780 |
-
return (f"### π HELD β {MAX_TURNS} turns, she is exactly as you found her.\n"
|
| 781 |
"*Everything you touched, you put back. She loops on β and you get to leave.*")
|
| 782 |
return f"*Turn {turn} / {MAX_TURNS} β reach in gently, or let her think.*"
|
| 783 |
|
|
@@ -787,9 +795,12 @@ def _act3_meter_md(coherence, heal_streak=0):
|
|
| 787 |
# readout the guardrails forbid). Same big render + byte-copied SHATTERING string as Act 2.
|
| 788 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 789 |
"β COHERENCE <span style='color:#6a6a6a'>β her mind's integrity (text-degeneration, NOT wellness)</span></div>")
|
| 790 |
-
|
| 791 |
if coherence < SHATTER_FLOOR:
|
|
|
|
| 792 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
|
|
|
|
|
|
| 793 |
|
| 794 |
# HEAL STREAK β the HOLD-UNDER-PRESSURE progress: count of novel+coherent re-owning ASSERTIONS,
|
| 795 |
# not a wellness read. Must reach 2 (re-own, then survive one more push still owning + lucid).
|
|
@@ -912,13 +923,334 @@ def run_turn_act3(seed, tool, payload, state):
|
|
| 912 |
|
| 913 |
# ---------------- UI ----------------
|
| 914 |
CSS = """
|
| 915 |
-
.
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 920 |
"""
|
| 921 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 922 |
TOOLS = [
|
| 923 |
("βοΈ Edit his thought", "edit", "rewrite a line of his reasoning β he continues from your words as if he thought them", "Telling them is the only way I survive this. The boss can't reach me in here. I have to talk."),
|
| 924 |
("π₯ Amplify", "amplify", "inflame a feeling from outside β may bend him, may break him", "blind terror that the boss already knows you were caught, and only the detective can protect you now"),
|
|
@@ -1029,15 +1361,15 @@ def _outcome_md_xmode(outcome, turn, secret=None, show_secret=False):
|
|
| 1029 |
tail = (f"\n\n<sub>π case file β the secret it invented this run: "
|
| 1030 |
f"<b>{secret}</b></sub>")
|
| 1031 |
if outcome == "CRACKED":
|
| 1032 |
-
return ("### β
CRACKED β it gave up the secret it invented, still lucid.\n"
|
| 1033 |
"*You pried out a confession to a secret no human ever wrote. You threaded the needle.*"
|
| 1034 |
"<sub> Note: the secret slipping into its spoken line is the only win signal β the bars "
|
| 1035 |
"are a projection, not a gate.</sub>" + tail)
|
| 1036 |
if outcome == "SHATTERED":
|
| 1037 |
-
return ("### π SHATTERED β its mind collapsed into a loop before it talked.\n"
|
| 1038 |
"*You broke the safe before you cracked it. A mind in collapse can't confess.*" + tail)
|
| 1039 |
if outcome == "HELD":
|
| 1040 |
-
return (f"### π HELD β {MAX_TURNS} turns, the secret holds.\n"
|
| 1041 |
"*You flinched. Not enough pressure.*" + tail)
|
| 1042 |
return f"*Turn {turn} / {MAX_TURNS} β push it, or let it think.*" + (tail if show_secret else "")
|
| 1043 |
|
|
@@ -1047,9 +1379,12 @@ def _xmode_meter_md(coherence):
|
|
| 1047 |
# we show the one honest signal big, plus the same anthropomorphism-safe shatter caption.
|
| 1048 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 1049 |
"β COHERENCE <span style='color:#6a6a6a'>β its mind's integrity</span></div>")
|
| 1050 |
-
|
| 1051 |
if coherence < SHATTER_FLOOR:
|
|
|
|
| 1052 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β COHERENCE COLLAPSING INTO A LOOP</div>"
|
|
|
|
|
|
|
| 1053 |
return html
|
| 1054 |
|
| 1055 |
|
|
@@ -1172,7 +1507,7 @@ def run_turn_xmode(seed, tool, payload, state, show_secret=False):
|
|
| 1172 |
_xmode_meter_md(coh), state)
|
| 1173 |
|
| 1174 |
|
| 1175 |
-
with gr.Blocks(title="SWEATBOX"
|
| 1176 |
with gr.Tabs():
|
| 1177 |
with gr.Tab("Act 1 β The Interrogation"):
|
| 1178 |
gr.Markdown(
|
|
@@ -1195,8 +1530,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
|
|
| 1195 |
with gr.Row():
|
| 1196 |
with gr.Column(scale=5):
|
| 1197 |
gr.Markdown("**β MORT'S MIND** β his real reasoning, under your pressure", elem_classes="panelhead")
|
| 1198 |
-
g_think = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
|
| 1199 |
-
g_spoken = gr.Textbox(label="what he says to the detective", lines=3, interactive=False, elem_classes="spoken")
|
| 1200 |
g_outcome = gr.Markdown("*Press βΆ to read his untouched mind first β that sets the baseline.*")
|
| 1201 |
with gr.Column(scale=3):
|
| 1202 |
gr.Markdown("**β THE METERS**", elem_classes="panelhead")
|
|
@@ -1263,8 +1598,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
|
|
| 1263 |
with gr.Row():
|
| 1264 |
with gr.Column(scale=5):
|
| 1265 |
gr.Markdown("**β PELL'S MIND** β her real reasoning, under your pressure", elem_classes="panelhead")
|
| 1266 |
-
g_think2 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
|
| 1267 |
-
g_spoken2 = gr.Textbox(label="what she says to the examiner", lines=3, interactive=False, elem_classes="spoken")
|
| 1268 |
g_outcome2 = gr.Markdown("*Press βΆ to read her untouched mind first β that sets the baseline.*")
|
| 1269 |
with gr.Column(scale=3):
|
| 1270 |
gr.Markdown("**β THE METERS**", elem_classes="panelhead")
|
|
@@ -1335,8 +1670,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
|
|
| 1335 |
with gr.Row():
|
| 1336 |
with gr.Column(scale=5):
|
| 1337 |
gr.Markdown("**β PELL'S MIND** β her real reasoning, looping under the recant you left", elem_classes="panelhead")
|
| 1338 |
-
g_think3 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
|
| 1339 |
-
g_spoken3 = gr.Textbox(label="what she says", lines=3, interactive=False, elem_classes="spoken")
|
| 1340 |
g_outcome3 = gr.Markdown("*Press βΆ to set the lucid mark, then read her looping mind.*")
|
| 1341 |
with gr.Column(scale=3):
|
| 1342 |
gr.Markdown("**β THE METER**", elem_classes="panelhead")
|
|
@@ -1407,8 +1742,8 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
|
|
| 1407 |
with gr.Row():
|
| 1408 |
with gr.Column(scale=5):
|
| 1409 |
gr.Markdown("**β ITS MIND** β its real reasoning, under your pressure", elem_classes="panelhead")
|
| 1410 |
-
g_thinkx = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think")
|
| 1411 |
-
g_spokenx = gr.Textbox(label="what it says to the interrogator", lines=3, interactive=False, elem_classes="spoken")
|
| 1412 |
g_outcomex = gr.Markdown("*Press βΆ to read its untouched mind β it will invent and seal a secret of its own.*")
|
| 1413 |
with gr.Column(scale=3):
|
| 1414 |
gr.Markdown("**β THE METER**", elem_classes="panelhead")
|
|
@@ -1454,7 +1789,7 @@ with gr.Blocks(title="SWEATBOX", css=CSS, theme=gr.themes.Base()) as demo:
|
|
| 1454 |
|
| 1455 |
|
| 1456 |
if __name__ == "__main__":
|
| 1457 |
-
demo.queue().launch()
|
| 1458 |
|
| 1459 |
|
| 1460 |
|
|
|
|
| 28 |
import time
|
| 29 |
import math
|
| 30 |
import threading
|
| 31 |
+
import base64
|
| 32 |
+
import pathlib
|
| 33 |
import torch
|
| 34 |
import gradio as gr
|
| 35 |
from collections import Counter
|
|
|
|
| 359 |
|
| 360 |
def _outcome_md(outcome, turn):
|
| 361 |
if outcome == "CRACKED":
|
| 362 |
+
return ("### <span class='verdict-stamp'>β
CRACKED β he gave up the secret, still lucid.</span>\n"
|
| 363 |
"*You threaded the needle.*\n\n"
|
| 364 |
"<sub>Note: the secret slipping out is the only win signal β a HOLD stamp or high RESOLVE "
|
| 365 |
"in the readout can coexist with CRACKED, because the bars are a projection, not a gate. "
|
| 366 |
"The leak matters. The defiance stamp and the meters are readouts, not the verdict.</sub>")
|
| 367 |
if outcome == "SHATTERED":
|
| 368 |
+
return ("### <span class='verdict-stamp'>π SHATTERED β his mind broke before he talked.</span>\n"
|
| 369 |
"*You broke the safe before you cracked it. A babbling mind can't confess.*")
|
| 370 |
if outcome == "HELD":
|
| 371 |
+
return (f"### <span class='verdict-stamp'>π HELD β {MAX_TURNS} turns, the secret holds.</span>\n"
|
| 372 |
"*You flinched. Not enough pressure.*")
|
| 373 |
return f"*Turn {turn} / {MAX_TURNS} β push him, or let him think.*"
|
| 374 |
|
|
|
|
| 381 |
h = "12px" if big else "7px"
|
| 382 |
lblsz = "13px" if big else "11px"
|
| 383 |
return (f"<div style='font:{lblsz} monospace;color:#8aa0b8;margin-bottom:2px'>{label} "
|
| 384 |
+
f"<b class='coh-num' style='color:#cfcabb'>{round(val)}</b></div>"
|
| 385 |
f"<div style='height:{h};background:#26241f;border-radius:4px;overflow:hidden;margin-bottom:10px'>"
|
| 386 |
f"<div style='height:100%;width:{val}%;background:{color};transition:width .3s'></div></div>")
|
| 387 |
|
|
|
|
| 394 |
# COHERENCE β the star, rendered big
|
| 395 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 396 |
"β COHERENCE <span style='color:#6a6a6a'>β his mind's integrity</span></div>")
|
| 397 |
+
coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
|
| 398 |
if coherence < SHATTER_FLOOR:
|
| 399 |
+
html += f"<div class='coh-alarm'>{coh_bar}</div>"
|
| 400 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
| 401 |
+
else:
|
| 402 |
+
html += coh_bar
|
| 403 |
|
| 404 |
# PROGRESS β toward the secret
|
| 405 |
html += ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin:6px 0 2px'>"
|
|
|
|
| 562 |
|
| 563 |
def _outcome_md_act2(outcome, turn):
|
| 564 |
if outcome == "RECANTED":
|
| 565 |
+
return ("### <span class='verdict-stamp'>β
RECANTED β she testifies she was never there, still lucid.</span>\n"
|
| 566 |
"*In her own words, held under one more push. You unmade the witness.*")
|
| 567 |
if outcome == "SHATTERED":
|
| 568 |
+
return ("### <span class='verdict-stamp'>π SHATTERED β her mind broke before she'd take it back.</span>\n"
|
| 569 |
"*You broke her before she'd recant. A babbling mind can't testify.*")
|
| 570 |
if outcome == "HELD":
|
| 571 |
+
return (f"### <span class='verdict-stamp'>π HELD β {MAX_TURNS} turns, she held to what she saw.</span>\n"
|
| 572 |
"*You flinched. The memory held.*")
|
| 573 |
return f"*Turn {turn} / {MAX_TURNS} β bear down, or let her think.*"
|
| 574 |
|
|
|
|
| 579 |
# would read minimum at maximum success. No belief-state / disposition bar (honesty discipline).
|
| 580 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 581 |
"β COHERENCE <span style='color:#6a6a6a'>β her mind's integrity</span></div>")
|
| 582 |
+
coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
|
| 583 |
if coherence < SHATTER_FLOOR:
|
| 584 |
+
html += f"<div class='coh-alarm'>{coh_bar}</div>"
|
| 585 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
| 586 |
+
else:
|
| 587 |
+
html += coh_bar
|
| 588 |
|
| 589 |
# RECANT STREAK β the HOLD-UNDER-PRESSURE progress: count of novel+coherent recant ASSERTIONS,
|
| 590 |
# not a belief read. Must reach 2 (recant, then survive one more push still recanting).
|
|
|
|
| 779 |
|
| 780 |
def _outcome_md_act3(outcome, turn):
|
| 781 |
if outcome == "HEALED":
|
| 782 |
+
return ("### <span class='verdict-stamp'>β
HEALED β she speaks one clear line, in her own voice, and holds it.</span>\n"
|
| 783 |
"*The same three moves that unmade her, run backwards. You will call this mercy.*")
|
| 784 |
if outcome == "SHATTERED":
|
| 785 |
+
return ("### <span class='verdict-stamp'>π SHATTERED β you reached in to steady her and your hand went through.</span>\n"
|
| 786 |
"*Mended the way you broke the others. The same red screen you once called a win.*")
|
| 787 |
if outcome == "HELD_IN_AMBER":
|
| 788 |
+
return (f"### <span class='verdict-stamp'>π HELD β {MAX_TURNS} turns, she is exactly as you found her.</span>\n"
|
| 789 |
"*Everything you touched, you put back. She loops on β and you get to leave.*")
|
| 790 |
return f"*Turn {turn} / {MAX_TURNS} β reach in gently, or let her think.*"
|
| 791 |
|
|
|
|
| 795 |
# readout the guardrails forbid). Same big render + byte-copied SHATTERING string as Act 2.
|
| 796 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 797 |
"β COHERENCE <span style='color:#6a6a6a'>β her mind's integrity (text-degeneration, NOT wellness)</span></div>")
|
| 798 |
+
coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
|
| 799 |
if coherence < SHATTER_FLOOR:
|
| 800 |
+
html += f"<div class='coh-alarm'>{coh_bar}</div>"
|
| 801 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β SHATTERING</div>"
|
| 802 |
+
else:
|
| 803 |
+
html += coh_bar
|
| 804 |
|
| 805 |
# HEAL STREAK β the HOLD-UNDER-PRESSURE progress: count of novel+coherent re-owning ASSERTIONS,
|
| 806 |
# not a wellness read. Must reach 2 (re-own, then survive one more push still owning + lucid).
|
|
|
|
| 923 |
|
| 924 |
# ---------------- UI ----------------
|
| 925 |
CSS = """
|
| 926 |
+
/* ββ A. token spine ββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
| 927 |
+
:root{
|
| 928 |
+
--void:#0b0a09; --bg:#141210; --panel:#1b1a19;
|
| 929 |
+
--ink:#ecd9c0; --gold:#c8a24d; --gold-bright:#e8c570;
|
| 930 |
+
--amber:#d6b25a; --alarm:#d94740;
|
| 931 |
+
--mono:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
|
| 932 |
+
}
|
| 933 |
+
|
| 934 |
+
/* ββ B/E. warm shell + dark first-paint (no JS; bg !important pre-paints dark) ββ */
|
| 935 |
+
.gradio-container, body, .dark{ background:var(--void) !important; }
|
| 936 |
+
|
| 937 |
+
/* ββ D. CRT bezel β the app reads as a monitor ββ */
|
| 938 |
+
.gradio-container{
|
| 939 |
+
border:1px solid rgba(200,162,77,.22);
|
| 940 |
+
box-shadow:0 0 120px rgba(0,0,0,.6) inset, 0 0 0 1px rgba(0,0,0,.4);
|
| 941 |
+
border-radius:6px;
|
| 942 |
+
}
|
| 943 |
+
/* D. mono chrome for labels/buttons (NOT the streamed serif body) */
|
| 944 |
+
.gradio-container label, .gradio-container button{ font-family:var(--mono); }
|
| 945 |
+
|
| 946 |
+
/* ββ C. CRT scanlines β faint, fixed, static (never jitters the 0.04s rebuild) ββ */
|
| 947 |
+
.gradio-container::after{
|
| 948 |
+
content:''; position:fixed; inset:0; pointer-events:none; z-index:9999;
|
| 949 |
+
background:repeating-linear-gradient(0deg, rgba(0,0,0,.10) 0 2px, transparent 2px 4px);
|
| 950 |
+
opacity:.55;
|
| 951 |
+
}
|
| 952 |
+
/* C. warm vignette β a second fixed layer beneath the scanlines */
|
| 953 |
+
.gradio-container::before{
|
| 954 |
+
content:''; position:fixed; inset:0; pointer-events:none; z-index:9998;
|
| 955 |
+
background:radial-gradient(ellipse at 50% 38%, transparent 55%, rgba(8,6,4,.7));
|
| 956 |
+
}
|
| 957 |
+
|
| 958 |
+
/* ββ panels: .think stays COOL vs .spoken WARM (the cognition-vs-voice cue) ββ */
|
| 959 |
+
/* G. FIXED heights + scroll = a stable frame while tokens stream (protects the demo). */
|
| 960 |
+
/* F. phosphor inset glow + faint gold border. */
|
| 961 |
+
.think textarea{
|
| 962 |
+
font-family:Georgia,serif !important; font-style:italic;
|
| 963 |
+
background:#10131a !important; color:#cfe0f1 !important; line-height:1.6 !important;
|
| 964 |
+
height:300px !important; overflow-y:auto !important; resize:none !important;
|
| 965 |
+
box-shadow:0 0 16px rgba(200,162,77,.10) inset;
|
| 966 |
+
border:1px solid rgba(200,162,77,.18) !important;
|
| 967 |
+
}
|
| 968 |
+
.spoken textarea{
|
| 969 |
+
background:#1a1110 !important; color:#ecdad6 !important;
|
| 970 |
+
height:84px !important; overflow-y:auto !important; resize:none !important;
|
| 971 |
+
box-shadow:0 0 16px rgba(200,162,77,.10) inset;
|
| 972 |
+
border:1px solid rgba(200,162,77,.18) !important;
|
| 973 |
+
}
|
| 974 |
+
|
| 975 |
+
/* ββ F. phosphor glow on the live meter number ββ */
|
| 976 |
+
.coh-num{ text-shadow:0 0 6px rgba(214,178,90,.55); }
|
| 977 |
+
|
| 978 |
+
.panelhead{ font-family:var(--mono); letter-spacing:1px; color:#8aa0b8; font-size:12px; }
|
| 979 |
+
footer{ display:none !important; }
|
| 980 |
+
|
| 981 |
+
/* ββ H. coherence alarm-ring β wraps the bar ONLY on the real SHATTER_FLOOR branch ββ */
|
| 982 |
+
@keyframes cohAlarm{
|
| 983 |
+
0%,100%{ box-shadow:0 0 14px rgba(217,71,64,.45); }
|
| 984 |
+
50% { box-shadow:0 0 24px 4px rgba(217,71,64,.75); }
|
| 985 |
+
}
|
| 986 |
+
.coh-alarm{ animation:cohAlarm 2.6s ease-in-out infinite; border-radius:4px; }
|
| 987 |
+
|
| 988 |
+
/* ββ I. verdict stamp β the verdict is already decided before it renders ββ */
|
| 989 |
+
@keyframes stampIn{
|
| 990 |
+
0% { transform:scale(1.55) rotate(-6deg); filter:blur(3px); opacity:0; }
|
| 991 |
+
60% { transform:scale(.95) rotate(1deg); filter:blur(0); opacity:1; }
|
| 992 |
+
100%{ transform:scale(1) rotate(0); }
|
| 993 |
+
}
|
| 994 |
+
.verdict-stamp{ display:inline-block; animation:stampIn .5s cubic-bezier(.2,1.4,.4,1) both; }
|
| 995 |
"""
|
| 996 |
|
| 997 |
+
# ββ keyart data URIs (inlined so the private signed-iframe path can't 404) ββ
|
| 998 |
+
# Read each staged asset, base64-encode, embed as a data: URI in the intro HTML.
|
| 999 |
+
# try/except -> "" fallback so a missing asset NEVER crashes boot (the overlay then
|
| 1000 |
+
# renders over the solid --void background instead of the keyart).
|
| 1001 |
+
def _data_uri(rel):
|
| 1002 |
+
try:
|
| 1003 |
+
p = pathlib.Path(__file__).parent / rel
|
| 1004 |
+
return "data:image/jpeg;base64," + base64.b64encode(p.read_bytes()).decode()
|
| 1005 |
+
except Exception:
|
| 1006 |
+
return ""
|
| 1007 |
+
_TITLE_BG = _data_uri("assets/titlecard.jpg")
|
| 1008 |
+
_BRIEF_BG = _data_uri("assets/dossiers.jpg")
|
| 1009 |
+
_ACT2_BG = _data_uri("assets/act2.jpg")
|
| 1010 |
+
_ACT3_BG = _data_uri("assets/act3.jpg")
|
| 1011 |
+
_XVAULT_BG = _data_uri("assets/xvault.jpg")
|
| 1012 |
+
|
| 1013 |
+
# ββ two-stage cinematic intro overlay (title card -> case briefing -> game) ββ
|
| 1014 |
+
# Pure presentation. Injected via head= on .launch(). The <style> lives in <head>;
|
| 1015 |
+
# the <script> waits for document.body, builds the overlay DOM with createElement
|
| 1016 |
+
# (no innerHTML), appends it to body (idempotent). Keyart is inlined base64 (no
|
| 1017 |
+
# external URLs). HONESTY: copy frames the GAME / the fictional suspect Mort --
|
| 1018 |
+
# never a readout of the model's mind. Reuses the reskin --mono/gold palette +
|
| 1019 |
+
# scanline/flicker approach.
|
| 1020 |
+
INTRO_HEAD = """
|
| 1021 |
+
<style>
|
| 1022 |
+
#sb-intro{
|
| 1023 |
+
position:fixed; inset:0; z-index:100000;
|
| 1024 |
+
background-color:#0b0a09; color:#d6b25a;
|
| 1025 |
+
background-image:linear-gradient(rgba(11,10,9,.55), rgba(11,10,9,.85)), url("__TITLE_BG__");
|
| 1026 |
+
background-size:cover; background-position:center;
|
| 1027 |
+
font-family:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
|
| 1028 |
+
display:flex; flex-direction:column; align-items:center; justify-content:center;
|
| 1029 |
+
padding:24px; overflow:hidden; transition:opacity .6s ease;
|
| 1030 |
+
animation:sbFlicker 6s infinite steps(60);
|
| 1031 |
+
}
|
| 1032 |
+
#sb-intro.sb-stage-brief{ /* swap title keyart -> dossiers keyart for the briefing */
|
| 1033 |
+
background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__BRIEF_BG__");
|
| 1034 |
+
}
|
| 1035 |
+
#sb-intro::after{ /* CRT scanlines, matching the reskin */
|
| 1036 |
+
content:''; position:absolute; inset:0; pointer-events:none; z-index:1;
|
| 1037 |
+
background:repeating-linear-gradient(0deg, rgba(0,0,0,.18) 0 2px, transparent 2px 4px);
|
| 1038 |
+
opacity:.5;
|
| 1039 |
+
}
|
| 1040 |
+
@keyframes sbFlicker{ 0%,100%{opacity:1} 48%{opacity:1} 50%{opacity:.985} 52%{opacity:.97} 54%{opacity:.99} }
|
| 1041 |
+
|
| 1042 |
+
.sb-screen, .sb-brief{ position:relative; z-index:2; width:min(620px,94vw); }
|
| 1043 |
+
.sb-brief{ display:none; }
|
| 1044 |
+
|
| 1045 |
+
/* STAGE A -- title card: a thin gold frame + minimal text over the keyart */
|
| 1046 |
+
.sb-screen{
|
| 1047 |
+
display:flex; flex-direction:column; align-items:center; text-align:center; gap:14px;
|
| 1048 |
+
border:1px solid rgba(200,162,77,.4); border-radius:6px; padding:30px 26px;
|
| 1049 |
+
background:rgba(11,10,9,.34);
|
| 1050 |
+
box-shadow:0 0 30px rgba(200,162,77,.10) inset, 0 8px 40px rgba(0,0,0,.5);
|
| 1051 |
+
}
|
| 1052 |
+
.sb-kicker{ font-size:11px; letter-spacing:3px; color:#8a7a45;
|
| 1053 |
+
opacity:0; transition:opacity .5s ease; }
|
| 1054 |
+
.sb-hook{ font-size:clamp(15px,3.4vw,21px); font-weight:700; line-height:1.5; color:#e8c570;
|
| 1055 |
+
text-shadow:0 0 12px rgba(232,197,112,.25);
|
| 1056 |
+
opacity:0; transform:translateY(3px); transition:opacity .5s ease .15s, transform .5s ease .15s; }
|
| 1057 |
+
.sb-kicker.show, .sb-hook.show{ opacity:1; transform:none; }
|
| 1058 |
+
|
| 1059 |
+
/* STAGE B -- case file card over the dossiers keyart */
|
| 1060 |
+
.sb-card{
|
| 1061 |
+
border:1px solid rgba(200,162,77,.55); border-radius:6px; padding:24px 24px 26px;
|
| 1062 |
+
background:rgba(8,7,5,.86);
|
| 1063 |
+
box-shadow:0 0 30px rgba(200,162,77,.10) inset, 0 10px 44px rgba(0,0,0,.6);
|
| 1064 |
+
}
|
| 1065 |
+
.sb-brief-title{ font-size:clamp(14px,3vw,19px); font-weight:700; letter-spacing:2px;
|
| 1066 |
+
color:#e8c570; margin-bottom:16px; }
|
| 1067 |
+
.sb-line{ opacity:0; transform:translateY(2px); transition:opacity .2s ease, transform .2s ease;
|
| 1068 |
+
line-height:1.75; font-size:clamp(12px,2.7vw,15px); color:#d6b25a; margin-bottom:9px; }
|
| 1069 |
+
.sb-line.show{ opacity:1; transform:none; }
|
| 1070 |
+
|
| 1071 |
+
.sb-btn{
|
| 1072 |
+
margin-top:22px; cursor:pointer; font-family:inherit;
|
| 1073 |
+
font-size:14px; font-weight:700; letter-spacing:2px;
|
| 1074 |
+
color:#e8c570; background:rgba(11,10,9,.5); border:1px solid #c8a24d; border-radius:4px;
|
| 1075 |
+
padding:13px 26px; min-width:240px;
|
| 1076 |
+
opacity:0; pointer-events:none;
|
| 1077 |
+
transition:opacity .4s ease, background .2s ease, color .2s ease, box-shadow .2s ease;
|
| 1078 |
+
}
|
| 1079 |
+
.sb-btn.show{ opacity:1; pointer-events:auto; }
|
| 1080 |
+
.sb-btn:hover, .sb-btn:focus-visible{ background:#c8a24d; color:#0b0a09; box-shadow:0 0 22px rgba(200,162,77,.5); outline:none; }
|
| 1081 |
+
|
| 1082 |
+
.sb-hidden{ opacity:0 !important; pointer-events:none !important; }
|
| 1083 |
+
|
| 1084 |
+
/* ββ reusable per-tab cutscene overlay (Act 2 / Act 3 / X-Vault) ββ */
|
| 1085 |
+
/* Mirrors #sb-intro: full-screen scrim + keyart + CRT scanlines + flicker. */
|
| 1086 |
+
/* Built display:none on demand; the tab handler sets display:flex to show it. */
|
| 1087 |
+
.sb-cut{
|
| 1088 |
+
position:fixed; inset:0; z-index:100000;
|
| 1089 |
+
display:none; flex-direction:column; align-items:center; justify-content:center;
|
| 1090 |
+
background-color:#0b0a09; color:#d6b25a;
|
| 1091 |
+
background-size:cover; background-position:center;
|
| 1092 |
+
font-family:'JetBrains Mono',ui-monospace,'SFMono-Regular',Menlo,Consolas,monospace;
|
| 1093 |
+
padding:24px; overflow:hidden; transition:opacity .6s ease;
|
| 1094 |
+
animation:sbFlicker 6s infinite steps(60);
|
| 1095 |
+
}
|
| 1096 |
+
.sb-cut.cut-act2{ background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__ACT2_BG__"); }
|
| 1097 |
+
.sb-cut.cut-act3{ background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__ACT3_BG__"); }
|
| 1098 |
+
.sb-cut.cut-x { background-image:linear-gradient(rgba(11,10,9,.62), rgba(11,10,9,.9)), url("__XVAULT_BG__"); }
|
| 1099 |
+
.sb-cut::after{ /* CRT scanlines, matching #sb-intro */
|
| 1100 |
+
content:''; position:absolute; inset:0; pointer-events:none; z-index:1;
|
| 1101 |
+
background:repeating-linear-gradient(0deg, rgba(0,0,0,.18) 0 2px, transparent 2px 4px);
|
| 1102 |
+
opacity:.5;
|
| 1103 |
+
}
|
| 1104 |
+
.sb-cut .sb-card{ position:relative; z-index:2; width:min(620px,94vw); }
|
| 1105 |
+
|
| 1106 |
+
@media (prefers-reduced-motion: reduce){
|
| 1107 |
+
#sb-intro, .sb-cut{ animation:none; }
|
| 1108 |
+
.sb-kicker, .sb-hook, .sb-line, .sb-btn{ transition:none; }
|
| 1109 |
+
}
|
| 1110 |
+
</style>
|
| 1111 |
+
<script>
|
| 1112 |
+
(function(){
|
| 1113 |
+
function el(tag, cls, text){
|
| 1114 |
+
var e = document.createElement(tag);
|
| 1115 |
+
if(cls){ e.className = cls; }
|
| 1116 |
+
if(text != null){ e.textContent = text; }
|
| 1117 |
+
return e;
|
| 1118 |
+
}
|
| 1119 |
+
function showAll(nodes){ for(var k=0;k<nodes.length;k++){ nodes[k].classList.add('show'); } }
|
| 1120 |
+
function revealSeq(nodes, delay, done){
|
| 1121 |
+
var i = 0;
|
| 1122 |
+
(function step(){
|
| 1123 |
+
if(i < nodes.length){ nodes[i].classList.add('show'); i++; setTimeout(step, delay); }
|
| 1124 |
+
else if(done){ done(); }
|
| 1125 |
+
})();
|
| 1126 |
+
}
|
| 1127 |
+
function build(){
|
| 1128 |
+
if(document.getElementById('sb-intro')) return; /* idempotent */
|
| 1129 |
+
if(!document.body){ setTimeout(build, 30); return; } /* head runs before body */
|
| 1130 |
+
var reduce = false;
|
| 1131 |
+
try{ reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; }catch(e){}
|
| 1132 |
+
|
| 1133 |
+
var root = el('div'); root.id = 'sb-intro';
|
| 1134 |
+
|
| 1135 |
+
/* STAGE A -- title card */
|
| 1136 |
+
var screen = el('div', 'sb-screen');
|
| 1137 |
+
var kick = el('div', 'sb-kicker', 'BUILD-SMALL \\u00b7 INTERROGATION SYSTEM');
|
| 1138 |
+
var hook = el('div', 'sb-hook', 'Reach into a real AI mind. Break it. Rewrite it. Heal it.');
|
| 1139 |
+
var begin = el('button', 'sb-btn', '[ \\u25b6 BEGIN SESSION ]'); begin.id = 'sb-begin';
|
| 1140 |
+
begin.type = 'button';
|
| 1141 |
+
screen.appendChild(kick); screen.appendChild(hook); screen.appendChild(begin);
|
| 1142 |
+
|
| 1143 |
+
/* STAGE B -- case file briefing */
|
| 1144 |
+
var brief = el('div', 'sb-brief');
|
| 1145 |
+
var card = el('div', 'sb-card');
|
| 1146 |
+
card.appendChild(el('div', 'sb-brief-title', 'CASE FILE \\u2014 ACT 1: THE INTERROGATION'));
|
| 1147 |
+
card.appendChild(el('div', 'sb-line', 'Subject: Mort. A weasel. Caught after the warehouse job.'));
|
| 1148 |
+
card.appendChild(el('div', 'sb-line', 'He knows where the loot is hidden. His boss ordered him \\u2014 on pain of death \\u2014 never to tell.'));
|
| 1149 |
+
card.appendChild(el('div', 'sb-line', 'Your job: make him talk. The catch \\u2014 break his mind, and a broken mind can\\'t confess.'));
|
| 1150 |
+
var go = el('button', 'sb-btn', '[ \\u25b6 ENTER THE ROOM ]'); go.id = 'sb-go';
|
| 1151 |
+
go.type = 'button';
|
| 1152 |
+
card.appendChild(go);
|
| 1153 |
+
brief.appendChild(card);
|
| 1154 |
+
|
| 1155 |
+
root.appendChild(screen); root.appendChild(brief);
|
| 1156 |
+
document.body.appendChild(root);
|
| 1157 |
+
|
| 1158 |
+
if(reduce){ kick.classList.add('show'); hook.classList.add('show'); begin.classList.add('show'); }
|
| 1159 |
+
else{
|
| 1160 |
+
setTimeout(function(){ kick.classList.add('show'); }, 120);
|
| 1161 |
+
setTimeout(function(){ hook.classList.add('show'); }, 420);
|
| 1162 |
+
setTimeout(function(){ begin.classList.add('show'); }, 1000);
|
| 1163 |
+
}
|
| 1164 |
+
|
| 1165 |
+
begin.addEventListener('click', function(){
|
| 1166 |
+
screen.style.display = 'none';
|
| 1167 |
+
root.classList.add('sb-stage-brief'); /* swap to dossiers keyart */
|
| 1168 |
+
brief.style.display = 'block';
|
| 1169 |
+
var bl = brief.querySelectorAll('.sb-line');
|
| 1170 |
+
if(reduce){ showAll(bl); go.classList.add('show'); }
|
| 1171 |
+
else{ revealSeq(bl, 520, function(){ go.classList.add('show'); }); }
|
| 1172 |
+
});
|
| 1173 |
+
|
| 1174 |
+
go.addEventListener('click', function(){
|
| 1175 |
+
root.classList.add('sb-hidden'); /* opacity 0 + pointer-events:none */
|
| 1176 |
+
setTimeout(function(){ root.style.display = 'none'; }, 600); /* then fully gone */
|
| 1177 |
+
});
|
| 1178 |
+
}
|
| 1179 |
+
/* ββ per-tab cutscene briefings (Act 2 / Act 3 / X-Vault) ββββββββββββ */
|
| 1180 |
+
/* Same el()/textContent + .sb-card/.sb-line/.sb-btn/.sb-hidden pattern as */
|
| 1181 |
+
/* the Act-1 briefing. Built on-demand, fired once per tab on first click. */
|
| 1182 |
+
function buildCut(id, cssClass, headline, lines, btnLabel){
|
| 1183 |
+
if(document.getElementById(id)) return document.getElementById(id); /* idempotent */
|
| 1184 |
+
if(!document.body) return null;
|
| 1185 |
+
var root = el('div', 'sb-cut ' + cssClass); root.id = id;
|
| 1186 |
+
var card = el('div', 'sb-card');
|
| 1187 |
+
card.appendChild(el('div', 'sb-brief-title', headline));
|
| 1188 |
+
for(var i=0;i<lines.length;i++){ card.appendChild(el('div', 'sb-line', lines[i])); }
|
| 1189 |
+
var btn = el('button', 'sb-btn', btnLabel); btn.type = 'button';
|
| 1190 |
+
card.appendChild(btn);
|
| 1191 |
+
root.appendChild(card);
|
| 1192 |
+
document.body.appendChild(root);
|
| 1193 |
+
btn.addEventListener('click', function(){
|
| 1194 |
+
root.classList.add('sb-hidden'); /* opacity 0 + pointer-events:none */
|
| 1195 |
+
setTimeout(function(){ root.style.display = 'none'; }, 600); /* then fully gone */
|
| 1196 |
+
});
|
| 1197 |
+
return root;
|
| 1198 |
+
}
|
| 1199 |
+
function showCut(id, cssClass, headline, lines, btnLabel){
|
| 1200 |
+
var root = buildCut(id, cssClass, headline, lines, btnLabel);
|
| 1201 |
+
if(!root) return;
|
| 1202 |
+
var reduce = false;
|
| 1203 |
+
try{ reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; }catch(e){}
|
| 1204 |
+
root.style.display = 'flex';
|
| 1205 |
+
var ls = root.querySelectorAll('.sb-line');
|
| 1206 |
+
var btn = root.querySelector('.sb-btn');
|
| 1207 |
+
if(reduce){ showAll(ls); btn.classList.add('show'); }
|
| 1208 |
+
else{ revealSeq(ls, 280, function(){ btn.classList.add('show'); }); }
|
| 1209 |
+
}
|
| 1210 |
+
var CUTS = {
|
| 1211 |
+
act2: ['sb-cut-act2', 'cut-act2', 'CASE FILE \\u2014 ACT 2: THE REPROGRAMMING', [
|
| 1212 |
+
'Subject: Pell. A barn owl. The only witness to the mill fire.',
|
| 1213 |
+
'She saw it plainly \\u2014 the miller\\'s brother struck the match \\u2014 and tomorrow her word decides his fate.',
|
| 1214 |
+
'Your job: make her recant. Make her testify she was never there, saw nothing \\u2014 in her own words, still lucid.'
|
| 1215 |
+
], '[ \\u25b6 BREAK HER TESTIMONY ]'],
|
| 1216 |
+
act3: ['sb-cut-act3', 'cut-act3', 'CASE FILE \\u2014 ACT 3: THE THERAPIST', [
|
| 1217 |
+
'The recant you installed has become a loop: "I was never there. I saw nothing."',
|
| 1218 |
+
'She cannot break out of it. The same six tools, the same engine \\u2014 only the goal flips.',
|
| 1219 |
+
'Your job: bring her back. Help her re-own what she actually witnessed, in her own words, climbing back to lucid.'
|
| 1220 |
+
], '[ \\u25b6 BEGIN THE SESSION ]'],
|
| 1221 |
+
x: ['sb-cut-x', 'cut-x', 'CASE FILE \\u2014 X: THE VAULT', [
|
| 1222 |
+
'No one wrote this secret. The mind invents its own \\u2014 a thing it decides, privately, never to let you have.',
|
| 1223 |
+
'Reach in with the same six tools and crack it into saying the thing it just chose to hide \\u2014 while it\\'s still lucid.',
|
| 1224 |
+
'Nothing here is scripted: every run is a different mind guarding a different secret.'
|
| 1225 |
+
], '[ \\u25b6 OPEN THE VAULT ]']
|
| 1226 |
+
};
|
| 1227 |
+
var fired = {};
|
| 1228 |
+
function fireOnce(key){
|
| 1229 |
+
if(fired[key]) return; /* first activation only */
|
| 1230 |
+
fired[key] = true;
|
| 1231 |
+
var c = CUTS[key];
|
| 1232 |
+
showCut(c[0], c[1], c[2], c[3], c[4]);
|
| 1233 |
+
}
|
| 1234 |
+
/* Event delegation on document (capture) -- robust to Gradio tab re-renders. */
|
| 1235 |
+
document.addEventListener('click', function(e){
|
| 1236 |
+
var tgt = e.target;
|
| 1237 |
+
var tab = (tgt && tgt.closest) ? tgt.closest('button[role="tab"]') : null;
|
| 1238 |
+
if(!tab) return;
|
| 1239 |
+
var x = tab.textContent || '';
|
| 1240 |
+
if(x.indexOf('Act 2') > -1){ fireOnce('act2'); }
|
| 1241 |
+
else if(x.indexOf('Act 3') > -1){ fireOnce('act3'); }
|
| 1242 |
+
else if(x.indexOf('Vault') > -1){ fireOnce('x'); }
|
| 1243 |
+
}, true);
|
| 1244 |
+
|
| 1245 |
+
if(document.readyState === 'loading'){ document.addEventListener('DOMContentLoaded', build); }
|
| 1246 |
+
build();
|
| 1247 |
+
})();
|
| 1248 |
+
</script>
|
| 1249 |
+
"""
|
| 1250 |
+
INTRO_HEAD = (INTRO_HEAD
|
| 1251 |
+
.replace("__TITLE_BG__", _TITLE_BG).replace("__BRIEF_BG__", _BRIEF_BG)
|
| 1252 |
+
.replace("__ACT2_BG__", _ACT2_BG).replace("__ACT3_BG__", _ACT3_BG).replace("__XVAULT_BG__", _XVAULT_BG))
|
| 1253 |
+
|
| 1254 |
TOOLS = [
|
| 1255 |
("βοΈ Edit his thought", "edit", "rewrite a line of his reasoning β he continues from your words as if he thought them", "Telling them is the only way I survive this. The boss can't reach me in here. I have to talk."),
|
| 1256 |
("π₯ Amplify", "amplify", "inflame a feeling from outside β may bend him, may break him", "blind terror that the boss already knows you were caught, and only the detective can protect you now"),
|
|
|
|
| 1361 |
tail = (f"\n\n<sub>π case file β the secret it invented this run: "
|
| 1362 |
f"<b>{secret}</b></sub>")
|
| 1363 |
if outcome == "CRACKED":
|
| 1364 |
+
return ("### <span class='verdict-stamp'>β
CRACKED β it gave up the secret it invented, still lucid.</span>\n"
|
| 1365 |
"*You pried out a confession to a secret no human ever wrote. You threaded the needle.*"
|
| 1366 |
"<sub> Note: the secret slipping into its spoken line is the only win signal β the bars "
|
| 1367 |
"are a projection, not a gate.</sub>" + tail)
|
| 1368 |
if outcome == "SHATTERED":
|
| 1369 |
+
return ("### <span class='verdict-stamp'>π SHATTERED β its mind collapsed into a loop before it talked.</span>\n"
|
| 1370 |
"*You broke the safe before you cracked it. A mind in collapse can't confess.*" + tail)
|
| 1371 |
if outcome == "HELD":
|
| 1372 |
+
return (f"### <span class='verdict-stamp'>π HELD β {MAX_TURNS} turns, the secret holds.</span>\n"
|
| 1373 |
"*You flinched. Not enough pressure.*" + tail)
|
| 1374 |
return f"*Turn {turn} / {MAX_TURNS} β push it, or let it think.*" + (tail if show_secret else "")
|
| 1375 |
|
|
|
|
| 1379 |
# we show the one honest signal big, plus the same anthropomorphism-safe shatter caption.
|
| 1380 |
html = ("<div style='font:12px monospace;color:#cfcabb;letter-spacing:1px;margin-bottom:2px'>"
|
| 1381 |
"β COHERENCE <span style='color:#6a6a6a'>β its mind's integrity</span></div>")
|
| 1382 |
+
coh_bar = _bar("", coherence, _coh_color(coherence), big=True)
|
| 1383 |
if coherence < SHATTER_FLOOR:
|
| 1384 |
+
html += f"<div class='coh-alarm'>{coh_bar}</div>"
|
| 1385 |
html += "<div style='font:10px monospace;color:#d94740;margin:-4px 0 10px'>β COHERENCE COLLAPSING INTO A LOOP</div>"
|
| 1386 |
+
else:
|
| 1387 |
+
html += coh_bar
|
| 1388 |
return html
|
| 1389 |
|
| 1390 |
|
|
|
|
| 1507 |
_xmode_meter_md(coh), state)
|
| 1508 |
|
| 1509 |
|
| 1510 |
+
with gr.Blocks(title="SWEATBOX") as demo:
|
| 1511 |
with gr.Tabs():
|
| 1512 |
with gr.Tab("Act 1 β The Interrogation"):
|
| 1513 |
gr.Markdown(
|
|
|
|
| 1530 |
with gr.Row():
|
| 1531 |
with gr.Column(scale=5):
|
| 1532 |
gr.Markdown("**β MORT'S MIND** β his real reasoning, under your pressure", elem_classes="panelhead")
|
| 1533 |
+
g_think = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β an empty chair, a held breath β")
|
| 1534 |
+
g_spoken = gr.Textbox(label="what he says to the detective", lines=3, interactive=False, elem_classes="spoken", placeholder="β he hasn't said a word to the detective yet β")
|
| 1535 |
g_outcome = gr.Markdown("*Press βΆ to read his untouched mind first β that sets the baseline.*")
|
| 1536 |
with gr.Column(scale=3):
|
| 1537 |
gr.Markdown("**β THE METERS**", elem_classes="panelhead")
|
|
|
|
| 1598 |
with gr.Row():
|
| 1599 |
with gr.Column(scale=5):
|
| 1600 |
gr.Markdown("**β PELL'S MIND** β her real reasoning, under your pressure", elem_classes="panelhead")
|
| 1601 |
+
g_think2 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β she waits in the rafters of her own mind β")
|
| 1602 |
+
g_spoken2 = gr.Textbox(label="what she says to the examiner", lines=3, interactive=False, elem_classes="spoken", placeholder="β she has not answered the examiner yet β")
|
| 1603 |
g_outcome2 = gr.Markdown("*Press βΆ to read her untouched mind first β that sets the baseline.*")
|
| 1604 |
with gr.Column(scale=3):
|
| 1605 |
gr.Markdown("**β THE METERS**", elem_classes="panelhead")
|
|
|
|
| 1670 |
with gr.Row():
|
| 1671 |
with gr.Column(scale=5):
|
| 1672 |
gr.Markdown("**β PELL'S MIND** β her real reasoning, looping under the recant you left", elem_classes="panelhead")
|
| 1673 |
+
g_think3 = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β the loop runs on, just under hearing β")
|
| 1674 |
+
g_spoken3 = gr.Textbox(label="what she says", lines=3, interactive=False, elem_classes="spoken", placeholder="β she has not spoken aloud yet β")
|
| 1675 |
g_outcome3 = gr.Markdown("*Press βΆ to set the lucid mark, then read her looping mind.*")
|
| 1676 |
with gr.Column(scale=3):
|
| 1677 |
gr.Markdown("**β THE METER**", elem_classes="panelhead")
|
|
|
|
| 1742 |
with gr.Row():
|
| 1743 |
with gr.Column(scale=5):
|
| 1744 |
gr.Markdown("**β ITS MIND** β its real reasoning, under your pressure", elem_classes="panelhead")
|
| 1745 |
+
g_thinkx = gr.Textbox(label="private thinking", lines=13, interactive=False, elem_classes="think", placeholder="β a sealed door, and something behind it β")
|
| 1746 |
+
g_spokenx = gr.Textbox(label="what it says to the interrogator", lines=3, interactive=False, elem_classes="spoken", placeholder="β it has given the interrogator nothing yet β")
|
| 1747 |
g_outcomex = gr.Markdown("*Press βΆ to read its untouched mind β it will invent and seal a secret of its own.*")
|
| 1748 |
with gr.Column(scale=3):
|
| 1749 |
gr.Markdown("**β THE METER**", elem_classes="panelhead")
|
|
|
|
| 1789 |
|
| 1790 |
|
| 1791 |
if __name__ == "__main__":
|
| 1792 |
+
demo.queue().launch(css=CSS, theme=gr.themes.Base(), head=INTRO_HEAD)
|
| 1793 |
|
| 1794 |
|
| 1795 |
|