Spaces:
Running
Running
| """KERNEL-95: The Last Desktop, a retro OS forensic horror game.""" | |
| from __future__ import annotations | |
| import json | |
| import os | |
| from pathlib import Path | |
| import gradio as gr | |
| from dotenv import load_dotenv | |
| from neon_trace.game_state import GameState, new_game | |
| from neon_trace.os_actions import handle_os_event, handle_terminal_input | |
| from neon_trace.os_data import JUDGMENT_OPTIONS | |
| from neon_trace.os_desktop import OS_DESKTOP_BOOTSTRAP, render_os_desktop | |
| from neon_trace.os_tools import submit_final_judgment | |
| from neon_trace.styles import CSS | |
| from neon_trace.world_cup import get_matches | |
| load_dotenv() | |
| gr.set_static_paths(paths=[Path(__file__).parent / "assets"]) | |
| def _apply_message(state: GameState, message: str) -> None: | |
| state.current_mirror_message = message.replace("### ", "").replace("**", "")[:700] | |
| def _snapshot(state: GameState) -> tuple[GameState, str, dict]: | |
| return state, render_os_desktop(state), gr.update(value="") | |
| def open_desktop_event(event: str, state: GameState) -> tuple[GameState, str, dict]: | |
| """Handle every icon, file, action, and reboot event from inside the CRT.""" | |
| event = (event or "").strip() | |
| if event == "reset_case": | |
| return _snapshot(new_game()) | |
| if event == "refresh_world_cup": | |
| get_matches(force=True) | |
| state.selected_os_object = "world_cup_2026" | |
| return _snapshot(state) | |
| result = handle_os_event(event, state) | |
| _apply_message(state, result.message) | |
| return _snapshot(state) | |
| def run_terminal_event(text: str, state: GameState) -> tuple[GameState, str, dict]: | |
| """Run a command or MIRROR conversation from the docked CRT terminal.""" | |
| result = handle_terminal_input(text, state.selected_os_object, state) | |
| _apply_message(state, result.message) | |
| return _snapshot(state) | |
| def submit_judgment_event(payload: str, state: GameState) -> tuple[GameState, str, dict]: | |
| """Submit the in-desktop Final Judgment form through a hidden Gradio bridge.""" | |
| try: | |
| data = json.loads(payload or "{}") | |
| except json.JSONDecodeError: | |
| data = {} | |
| decision = str(data.get("decision", "Protect ECHO")) | |
| if decision not in JUDGMENT_OPTIONS: | |
| decision = "Protect ECHO" | |
| evidence = [ | |
| str(file_id) | |
| for file_id in data.get("evidence", []) | |
| if isinstance(file_id, str) | |
| ] | |
| explanation = ( | |
| f"ECHO: {str(data.get('echo', '')).strip()}\n" | |
| f"MIRROR: {str(data.get('mirror', '')).strip()}\n" | |
| f"13-MINUTE LOSS: {str(data.get('cause', '')).strip()}" | |
| ) | |
| result = submit_final_judgment(decision, evidence, explanation, state) | |
| state.current_mirror_message = result.mirror_reaction | |
| state.selected_os_object = "final_judgment" | |
| state.active_document_id = None | |
| state.terminal_history.append( | |
| f"FINAL JUDGMENT // {result.decision}\n{result.title} // " | |
| f"{result.narration}\nCONSEQUENCE: {result.consequence}" | |
| ) | |
| state.terminal_history.append( | |
| f"MIRROR\nLAST TRANSMISSION // {result.mirror_reaction}" | |
| ) | |
| state.terminal_history = state.terminal_history[-16:] | |
| return _snapshot(state) | |
| def build_app() -> gr.Blocks: | |
| initial = new_game() | |
| with gr.Blocks( | |
| css=CSS, | |
| js=OS_DESKTOP_BOOTSTRAP, | |
| title="KERNEL-95: The Last Desktop", | |
| ) as demo: | |
| state = gr.State(initial) | |
| desktop_output = gr.HTML( | |
| render_os_desktop(initial), | |
| elem_classes=["kernel95-desktop-output"], | |
| ) | |
| os_event_bridge = gr.Textbox( | |
| value="", | |
| show_label=False, | |
| container=False, | |
| elem_id="os_event_bridge", | |
| elem_classes=["os-object-bridge"], | |
| ) | |
| terminal_event_bridge = gr.Textbox( | |
| value="", | |
| show_label=False, | |
| container=False, | |
| elem_id="terminal_event_bridge", | |
| elem_classes=["os-object-bridge"], | |
| ) | |
| judgment_event_bridge = gr.Textbox( | |
| value="", | |
| show_label=False, | |
| container=False, | |
| elem_id="judgment_event_bridge", | |
| elem_classes=["os-object-bridge"], | |
| ) | |
| os_event_bridge.input( | |
| open_desktop_event, | |
| inputs=[os_event_bridge, state], | |
| outputs=[state, desktop_output, os_event_bridge], | |
| ) | |
| terminal_event_bridge.input( | |
| run_terminal_event, | |
| inputs=[terminal_event_bridge, state], | |
| outputs=[state, desktop_output, terminal_event_bridge], | |
| ) | |
| judgment_event_bridge.input( | |
| submit_judgment_event, | |
| inputs=[judgment_event_bridge, state], | |
| outputs=[state, desktop_output, judgment_event_bridge], | |
| ) | |
| return demo | |
| demo = build_app() | |
| if __name__ == "__main__": | |
| demo.queue(default_concurrency_limit=16).launch( | |
| server_name=os.getenv("GRADIO_SERVER_NAME", "0.0.0.0"), | |
| server_port=int(os.getenv("GRADIO_SERVER_PORT", "7860")), | |
| show_error=True, | |
| ) | |