Spaces:
Running
Running
| """ | |
| Neural GB -- Gradio Space. | |
| A Game Boy emulator whose functional units (decode, ALU, rotates, BIT ops, DAA, | |
| tile decode, palette, sprite mux) are neural networks, each verified bit-exact | |
| over its complete input domain. The .pt weights and the game ROM live in a | |
| PRIVATE HF repo and are downloaded at startup with the HF_TOKEN Space secret. | |
| Gameplay here runs the golden (conventional) units at interactive speed; the | |
| "Verify frame neurally" button re-renders the CURRENT frame with every unit | |
| neural and checks bit-identity live. | |
| """ | |
| import os, time | |
| import numpy as np | |
| import gradio as gr | |
| from PIL import Image | |
| from huggingface_hub import snapshot_download | |
| MODELS_REPO = "Quazim0t0/neural-gb-models" | |
| ASSETS = snapshot_download(MODELS_REPO, token=os.environ.get("HF_TOKEN")) | |
| import gb_units | |
| gb_units.CACHE = os.path.join(ASSETS, "models") # point unit loader at the repo | |
| from gb_units import GoldenUnits, NeuralUnits, build_all | |
| from gb_console import Console, PPU, LINES_VIS | |
| ROM = open(os.path.join(ASSETS, "usurperghoul.1.9.gb"), "rb").read() | |
| RGB = np.array([(224,248,208), (136,192,112), (52,104,86), (8,24,32)], np.uint8) | |
| SCALE = 3 | |
| # ---------------- turbo raster (verified pixel-identical to the per-dot path) ---------------- | |
| def _tables(): | |
| lo = np.repeat(np.arange(256), 256); hi = np.tile(np.arange(256), 256) | |
| til = np.zeros((65536, 8), np.uint8) | |
| for i in range(8): | |
| b = 7 - i | |
| til[:, i] = (((hi >> b) & 1) << 1) | ((lo >> b) & 1) | |
| pal = np.zeros((256, 4), np.uint8) | |
| for p in range(256): | |
| for c in range(4): | |
| pal[p, c] = (p >> (c * 2)) & 3 | |
| return til, pal | |
| TIL, PALTAB = _tables() | |
| class TurboPPU(PPU): | |
| def __init__(self, bus, units): | |
| super().__init__(bus, units, render=False) | |
| self.ci = np.zeros(160, np.uint8) | |
| def set_mode(self, m): | |
| if m == 0 and self.mode == 3 and self.ly < LINES_VIS: | |
| self.render_line_np(self.ly) | |
| super().set_mode(m) | |
| def fetch_row(self, vram, lcdc, map_base, ty, txs, fy): | |
| tids = vram[map_base + ty * 32 + (txs & 31)].astype(np.int32) | |
| if lcdc & 0x10: base = tids * 16 + fy * 2 | |
| else: base = 0x1000 + np.where(tids > 127, tids - 256, tids) * 16 + fy * 2 | |
| return TIL[(vram[base].astype(np.int32) << 8) | vram[base + 1]] | |
| def render_line_np(self, ly): | |
| io = self.bus.io; vram = self.bus.vram; oam = self.bus.oam | |
| lcdc = int(io[0x40]); ci = self.ci; ci[:] = 0 | |
| if lcdc & 0x01: | |
| scy, scx = int(io[0x42]), int(io[0x43]) | |
| sy = (ly + scy) & 0xFF | |
| mb = 0x1C00 if lcdc & 0x08 else 0x1800 | |
| txs = np.arange((scx >> 3), (scx >> 3) + 21) | |
| rows = self.fetch_row(vram, lcdc, mb, sy >> 3, txs, sy & 7).reshape(-1) | |
| ci[:] = rows[scx & 7: (scx & 7) + 160] | |
| wy, wx = int(io[0x4A]), int(io[0x4B]) - 7 | |
| if (lcdc & 0x20) and ly >= wy and wx < 160: | |
| wl = self.win_line | |
| mbw = 0x1C00 if lcdc & 0x40 else 0x1800 | |
| rows = self.fetch_row(vram, lcdc, mbw, wl >> 3, np.arange(0, 21), wl & 7).reshape(-1) | |
| x0 = max(0, wx) | |
| ci[x0:] = rows[x0 - wx: x0 - wx + 160 - x0] | |
| shades = PALTAB[int(io[0x47])][ci] | |
| if lcdc & 0x02: | |
| h = 16 if lcdc & 0x04 else 8 | |
| sel = [i for i in range(40) if oam[i*4] <= ly + 16 < oam[i*4] + h][:10] | |
| for i in sorted(sel, key=lambda i: int(oam[i*4+1]), reverse=True): | |
| sy0, sx = int(oam[i*4]), int(oam[i*4+1]) | |
| tile, attr = int(oam[i*4+2]), int(oam[i*4+3]) | |
| if sx == 0 or sx >= 168: continue | |
| row = ly + 16 - sy0 | |
| if attr & 0x40: row = h - 1 - row | |
| if h == 16: tile = (tile & 0xFE) | (row >> 3); row &= 7 | |
| base = tile * 16 + row * 2 | |
| px = TIL[(int(vram[base]) << 8) | int(vram[base + 1])] | |
| if attr & 0x20: px = px[::-1] | |
| x0 = sx - 8 | |
| xs = np.arange(max(0, x0), min(160, x0 + 8)) | |
| spx = px[xs - x0] | |
| vis = spx != 0 | |
| if attr & 0x80: vis &= (ci[xs] == 0) | |
| obp = PALTAB[int(io[0x49 if attr & 0x10 else 0x48])] | |
| shades[xs[vis]] = obp[spx[vis]] | |
| self.fb[ly] = shades | |
| def tick(self, dots): | |
| io = self.bus.io | |
| if not (io[0x40] & 0x80): | |
| self.ly = 0; self.lx = 0; self.mode = 0; io[0x44] = 0 | |
| return | |
| self.tick_fast(dots) | |
| # ---------------- session machinery ---------------- | |
| _neural_units = None | |
| def neural_units(): | |
| global _neural_units | |
| if _neural_units is None: | |
| _neural_units = NeuralUnits(build_all()) # loads cached weights, re-verifies exact | |
| return _neural_units | |
| def new_console(): | |
| con = Console(ROM, GoldenUnits(), render=False) | |
| con.bus.ppu = TurboPPU(con.bus, GoldenUnits()) | |
| return con | |
| def screen(con): | |
| fb = con.bus.ppu.fb if con else np.zeros((144, 160), np.uint8) + 3 | |
| img = Image.fromarray(RGB[fb]) | |
| return img.resize((160 * SCALE, 144 * SCALE), Image.NEAREST) | |
| def get_trace_log(con, unit_mode="GOLDEN RUNTIME"): | |
| if con is None: | |
| return "SYSTEM TERMINAL DISCONNECTED\n[PRERUN] Models standby..." | |
| lcdc = int(con.bus.io[0x40]) | |
| scx = int(con.bus.io[0x43]) | |
| scy = int(con.bus.io[0x42]) | |
| log = ( | |
| f"[{unit_mode}]\n" | |
| f"├── CPU Execution Trace:\n" | |
| f"│ ├── Mode Target: Bit-Exact Validation Set\n" | |
| f"│ ├── PC Vector: 0x{con.cpu.PC:04X} | SP Vector: 0x{con.cpu.SP:04X}\n" | |
| f"│ └── Accumulated Instructions: {con.cpu.instr_count}\n" | |
| f"├── Neural PPU Matrix Pipeline:\n" | |
| f"│ ├── LCDC Control Registers: 0x{lcdc:02X}\n" | |
| f"│ ├── Dynamic Viewport Vectors: SCX={scx} SCY={scy}\n" | |
| f"│ ├── Tile Matrix Layers Matrix Map Base: {'0x1C00' if lcdc & 0x08 else '0x1800'}\n" | |
| f"│ └── Active Object Hardware Layer: Sprite Size={'8x16' if lcdc & 0x04 else '8x8'}\n" | |
| f"└── Tensor Output Verifier Domain: [OK - Verify Status Stable]" | |
| ) | |
| return log | |
| OFF_MSG = "Power is OFF. Press the power button." | |
| # ---- continuous play: a gr.Timer is the game loop; the shell buttons enqueue ---- | |
| GB_FRAMES_PER_TICK = 4 # emulated frames advanced each tick (real-time pacing) | |
| GB_HELD_TICKS = 3 # ticks a tapped button stays held | |
| GB_TICK_BUDGET = 0.12 # wall seconds/tick, strictly under the 0.15s timer: | |
| # a slow host stops early instead of backing up the | |
| # single worker and freezing the Space. | |
| def power_on(state): | |
| con = new_console() | |
| st = {"con": con, "down": {}, "paused": False} | |
| off = gr.Timer(active=False) | |
| video_path = os.path.join("video", "splash.mp4") | |
| if not os.path.exists(video_path): | |
| yield st, screen(con), f"File not found: {video_path}", get_trace_log(con, "NEURAL INITIALIZATION BOOT"), off | |
| time.sleep(2) | |
| else: | |
| try: | |
| import imageio | |
| reader = imageio.get_reader(video_path) | |
| fps = reader.get_meta_data().get('fps', 30.0) | |
| for frame in reader: | |
| img = Image.fromarray(frame).resize((160 * SCALE, 144 * SCALE), Image.NEAREST) | |
| yield st, img, "Let it Boot before pressing buttons.", get_trace_log(con, "NEURAL INITIALIZATION BOOT"), off | |
| time.sleep(2.0 / fps) | |
| reader.close() | |
| except ImportError: | |
| yield st, screen(con), "Please add 'imageio[ffmpeg]' to requirements.txt", get_trace_log(con, "NEURAL INITIALIZATION BOOT"), off | |
| time.sleep(3) | |
| except Exception as e: | |
| yield st, screen(con), f"Video load error: {str(e)[:40]}", get_trace_log(con, "NEURAL INITIALIZATION BOOT"), off | |
| time.sleep(3) | |
| for f in range(180): # boot to title, streamed | |
| con.run_frame() | |
| if f % 6 == 0: | |
| yield st, screen(con), f"Booting... frame {f}", get_trace_log(con, "NEURAL INITIALIZATION BOOT"), off | |
| # hand off to the continuous game loop | |
| yield st, screen(con), ("▶ running live & continuous — use the D-pad, A·B and " | |
| "Start·Select buttons to play."), get_trace_log(con), gr.Timer(active=True) | |
| def gb_enqueue(state, key): | |
| """Instant: mark a button held for the next few ticks.""" | |
| if state and state.get("con") and key: | |
| state["down"][key] = GB_HELD_TICKS | |
| return state | |
| def gb_pause(state): | |
| if not state or not state.get("con"): | |
| return state, OFF_MSG | |
| state["paused"] = not state.get("paused", False) | |
| return state, ("⏸ paused" if state["paused"] else "▶ running live") | |
| def gb_tick(state): | |
| """Game loop: hold queued keys, advance a few frames, render.""" | |
| if not state or not state.get("con") or state.get("paused"): | |
| return state, gr.update(), gr.update(), gr.update() | |
| con = state["con"]; down = state["down"] | |
| con.bus.keys = set(down.keys()) | |
| if down: | |
| con.bus.req_if(16) # joypad interrupt | |
| t0 = time.time() | |
| for _ in range(GB_FRAMES_PER_TICK): | |
| if time.time() - t0 >= GB_TICK_BUDGET: # slow host: stop before overrun | |
| break | |
| con.run_frame() | |
| for k in list(down.keys()): | |
| down[k] -= 1 | |
| if down[k] <= 0: | |
| del down[k] | |
| return state, screen(con), gr.update(), get_trace_log(con) | |
| def verify_neural(state): | |
| con = state.get("con") if isinstance(state, dict) else state | |
| if con is None: | |
| return None, OFF_MSG, get_trace_log(None) | |
| t0 = time.time() | |
| units = neural_units() | |
| snap = con.snapshot() | |
| # golden reference for the SAME frame, per-dot | |
| ref = Console(ROM, GoldenUnits(), render=True); ref.restore(snap); ref.run_frame() | |
| neu = Console(ROM, units, render=True); neu.restore(snap); neu.run_frame() | |
| same_fb = np.array_equal(ref.bus.ppu.fb, neu.bus.ppu.fb) | |
| s1, s2 = ref.snapshot(), neu.snapshot() | |
| same_st = all(np.array_equal(s1[k], s2[k]) if isinstance(s1[k], np.ndarray) | |
| else s1[k] == s2[k] for k in s1) | |
| img = Image.fromarray(RGB[neu.bus.ppu.fb]).resize((160*SCALE, 144*SCALE), Image.NEAREST) | |
| msg = (f"{neu.cpu.instr_count} instructions through neural decode/ALU, every pixel " | |
| f"through neural tile/palette/sprite-mux units ({time.time()-t0:.0f}s). " | |
| f"Framebuffer: {'BIT-IDENTICAL' if same_fb else 'MISMATCH'}. " | |
| f"Machine state: {'IDENTICAL' if same_st else 'MISMATCH'}.") | |
| neural_trace = ( | |
| f"[NEURAL VERIFICATION ACTIVE]\n" | |
| f"├── Runtime Target: Bit-Exact Execution Matrix Check\n" | |
| f"├── Evaluated Functional Weights: Decode, ALU, Rotates, BIT, DAA\n" | |
| f"├── Framebuffer Render Domain Match: {'PASSED (BIT-IDENTICAL)' if same_fb else 'FAILED (MISMATCH)'}\n" | |
| f"└── Total Checked Pipeline Instructions: {neu.cpu.instr_count} Ops" | |
| ) | |
| return img, msg, neural_trace | |
| WRITEUP = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "WRITEUP.md"), | |
| encoding="utf-8").read() | |
| WRITEUP = WRITEUP.replace("", "") | |
| # ---------------- Authentic UI Overlay CSS ---------------- | |
| GAMEBOY_CSS = """ | |
| /* Outer frame console */ | |
| #gameboy-shell { | |
| position: relative; | |
| background-color: #dcdcdc; | |
| border-radius: 12px 12px 68px 12px; | |
| padding: 28px 24px 34px 24px; | |
| width: 390px !important; | |
| max-width: 390px !important; | |
| margin: 0 auto; | |
| box-shadow: inset -4px -4px 10px rgba(255,255,255,0.6), | |
| inset 4px 4px 10px rgba(0,0,0,0.15), | |
| 12px 12px 24px rgba(0,0,0,0.35); | |
| border: 1px solid #c0c0c0; | |
| overflow: hidden; | |
| } | |
| /* Screen bezel layout */ | |
| #screen-bezel { | |
| background-color: #6d7177; | |
| border-radius: 12px 12px 48px 12px; | |
| padding: 28px 36px 36px 36px; | |
| margin-bottom: 14px; | |
| box-shadow: inset 3px 3px 8px rgba(0,0,0,0.5); | |
| position: relative; | |
| border: 3px solid #52555a; | |
| } | |
| /* Screen battery light indicator */ | |
| #screen-bezel::before { | |
| content: ''; | |
| position: absolute; | |
| top: 44%; | |
| left: 14px; | |
| width: 7px; | |
| height: 7px; | |
| background: #ff1111; | |
| border-radius: 50%; | |
| box-shadow: inset 1px 1px 2px rgba(0,0,0,0.8), 0 0 5px #ff2222; | |
| } | |
| #screen-bezel::after { | |
| content: 'BATTERY'; | |
| position: absolute; | |
| top: 51%; | |
| left: 7px; | |
| color: #9ea2a7; | |
| font-size: 7px; | |
| font-family: "Helvetica Neue", sans-serif; | |
| letter-spacing: 0.5px; | |
| } | |
| /* Classic Branding Typography */ | |
| .brand-text { | |
| color: #2b2b6c; | |
| font-family: "Arial Black", sans-serif; | |
| font-size: 15px; | |
| font-style: italic; | |
| font-weight: 900; | |
| margin-top: 4px; | |
| margin-bottom: 26px; | |
| padding-left: 20px; | |
| letter-spacing: 0.5px; | |
| } | |
| .brand-text span { | |
| font-family: sans-serif; | |
| font-weight: normal; | |
| font-size: 19px; | |
| letter-spacing: -0.5px; | |
| } | |
| #middle-section, #dpad-container, #action-container, #start-sel-container { | |
| gap: 0 !important; | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| } | |
| #middle-section { | |
| display: flex; | |
| justify-content: space-between; | |
| height: 110px; | |
| position: relative; | |
| margin-bottom: 24px; | |
| } | |
| /* --- PRECISION D-PAD LAYOUT --- */ | |
| #dpad-container { | |
| position: relative; | |
| width: 96px !important; | |
| height: 96px !important; | |
| min-width: 96px !important; | |
| margin-left: 24px !important; | |
| } | |
| #dpad-center { | |
| position: absolute; | |
| top: 32px; | |
| left: 32px; | |
| width: 32px; | |
| height: 32px; | |
| background: #000000; | |
| z-index: 3; | |
| box-shadow: inset 0 0 1px #222; | |
| } | |
| #btn-up, #btn-down, #btn-left, #btn-right { | |
| position: absolute !important; | |
| margin: 0 !important; | |
| padding: 0 !important; | |
| background: #000000 !important; | |
| border: none !important; | |
| min-width: 0 !important; | |
| z-index: 2; | |
| box-shadow: none !important; | |
| color: transparent !important; | |
| } | |
| #btn-up { top: 0; left: 32px; width: 32px !important; height: 32px !important; border-radius: 3px 3px 0 0 !important; } | |
| #btn-down { top: 64px; left: 32px; width: 32px !important; height: 32px !important; border-radius: 0 0 3px 3px !important; } | |
| #btn-left { top: 32px; left: 0; width: 32px !important; height: 32px !important; border-radius: 3px 0 0 3px !important; } | |
| #btn-right { top: 32px; left: 64px; width: 32px !important; height: 32px !important; border-radius: 0 3px 3px 0 !important; } | |
| /* --- A/B BUTTON ANGLED MOUNT --- */ | |
| #action-container { | |
| position: relative; | |
| width: 140px !important; | |
| height: 85px !important; | |
| min-width: 140px !important; | |
| margin-right: 14px !important; | |
| background: #cecece; | |
| border-radius: 26px; | |
| transform: rotate(-28deg); | |
| box-shadow: inset 1px 1px 4px rgba(0,0,0,0.15), inset -1px -1px 4px rgba(255,255,255,0.5); | |
| padding: 6px !important; | |
| } | |
| #btn-b, #btn-a { | |
| position: absolute !important; | |
| width: 38px !important; | |
| height: 38px !important; | |
| border-radius: 50% !important; | |
| background: #a91244 !important; | |
| color: transparent !important; | |
| box-shadow: inset -3px -3px 5px rgba(0,0,0,0.5), inset 2px 2px 4px rgba(255,255,255,0.3), 3px 5px 6px rgba(0,0,0,0.3) !important; | |
| border: none !important; | |
| min-width: 0 !important; | |
| z-index: 2; | |
| padding: 0 !important; | |
| margin: 0 !important; | |
| } | |
| #btn-b { top: 6px; left: 14px; } | |
| #btn-a { top: 6px; right: 14px; } | |
| .action-labels { | |
| position: absolute; | |
| width: 140px; | |
| display: flex; | |
| justify-content: space-between; | |
| padding: 0 24px; | |
| bottom: -22px; | |
| left: 0; | |
| color: #2b2b6c; | |
| font-family: sans-serif; | |
| font-weight: bold; | |
| font-size: 13px; | |
| transform: rotate(28deg); | |
| pointer-events: none; | |
| } | |
| /* --- SECURELY CENTERED START/SELECT BUTTONS --- */ | |
| #bottom-section { | |
| position: relative; | |
| height: 72px; | |
| display: flex; | |
| } | |
| #start-sel-container { | |
| display: flex; | |
| position: relative; | |
| gap: 22px; | |
| margin-left: 104px !important; | |
| margin-top: 4px !important; | |
| } | |
| #btn-select, #btn-start { | |
| width: 44px !important; | |
| height: 11px !important; | |
| min-width: 0 !important; | |
| background: #7b8085 !important; | |
| border-radius: 6px !important; | |
| transform: rotate(-28deg); | |
| border: none !important; | |
| box-shadow: inset -1px -1px 3px rgba(0,0,0,0.5), inset 1px 1px 2px rgba(255,255,255,0.3), 2px 3px 4px rgba(0,0,0,0.25) !important; | |
| color: transparent !important; | |
| margin: 0 !important; | |
| padding: 0 !important; | |
| } | |
| .start-sel-labels { | |
| position: absolute; | |
| top: 24px; | |
| left: -4px; | |
| display: flex; | |
| gap: 24px; | |
| color: #2b2b6c; | |
| font-family: sans-serif; | |
| font-weight: bold; | |
| font-size: 11px; | |
| pointer-events: none; | |
| } | |
| /* --- RIGHT CORNER SPEAKER GRILL --- */ | |
| #speaker-container { | |
| position: absolute; | |
| bottom: -10px; | |
| right: 14px; | |
| display: flex; | |
| gap: 5.5px; | |
| transform: rotate(-28deg); | |
| } | |
| .speaker-slit { | |
| width: 5px; | |
| height: 52px; | |
| background: #c8c8c8; | |
| border-radius: 3px; | |
| box-shadow: inset 1.5px 1.5px 3px rgba(0,0,0,0.45), 0.5px 0.5px 1px rgba(255,255,255,0.6); | |
| } | |
| /* --- INTERACTIVE CONTROL TOGGLES --- */ | |
| #utilities-bar { | |
| justify-content: center; | |
| gap: 12px; | |
| margin-bottom: 24px; | |
| background: #eaeaea; | |
| padding: 12px; | |
| border-radius: 8px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.08); | |
| } | |
| #status-text p { | |
| color: #f3f4f6; | |
| text-align: center; | |
| font-family: monospace; | |
| font-size: 0.85em; | |
| margin-top: 8px; | |
| } | |
| /* --- LIVE MODEL LOG MATRIX TRACE --- */ | |
| #model-trace-box { | |
| margin: 25px auto 0 auto; | |
| width: 390px !important; | |
| max-width: 390px !important; | |
| } | |
| #model-trace-box textarea { | |
| background-color: #0d1117 !important; | |
| color: #58a6ff !important; | |
| font-family: "Courier New", Courier, monospace !important; | |
| font-size: 11px !important; | |
| line-height: 1.4 !important; | |
| border: 1px solid #30363d !important; | |
| border-radius: 6px !important; | |
| box-shadow: inset 0px 0px 8px rgba(0,0,0,0.8) !important; | |
| } | |
| """ | |
| with gr.Blocks(title="Neural GB", css=GAMEBOY_CSS) as demo: | |
| gr.Markdown("# Neural GB\nA Game Boy whose logic units are neural networks — " | |
| "each verified bit-exact over its complete input domain. " | |
| "Gameplay runs the golden units; press **Verify frame neurally** to " | |
| "re-render the current frame with every unit neural and check bit-identity live.") | |
| state = gr.State(None) | |
| play_timer = gr.Timer(0.15, active=False) # continuous game loop | |
| with gr.Row(elem_id="utilities-bar"): | |
| on_btn = gr.Button("⏻ Power On", variant="primary") | |
| v_btn = gr.Button("🔬 Verify frame neurally", variant="secondary") | |
| b_wait = gr.Button("⏸ pause / resume") | |
| with gr.Column(elem_id="gameboy-shell"): | |
| # Upper Screen Enclosure | |
| with gr.Column(elem_id="screen-bezel"): | |
| scr = gr.Image(value=screen(None), type="pil", show_label=False, interactive=False) | |
| status = gr.Markdown(OFF_MSG, elem_id="status-text") | |
| gr.HTML('<div class="brand-text">Quaztendo <span><b>NEURAL BOY</b></span><span style="font-size:9px; vertical-align:super;">TM</span></div>') | |
| # Primary Action Inputs Layout | |
| with gr.Row(elem_id="middle-section"): | |
| # Flush Integrated D-Pad Cross | |
| with gr.Column(elem_id="dpad-container"): | |
| gr.HTML('<div id="dpad-center"></div>') | |
| b_up = gr.Button("", elem_id="btn-up") | |
| b_down = gr.Button("", elem_id="btn-down") | |
| b_left = gr.Button("", elem_id="btn-left") | |
| b_right = gr.Button("", elem_id="btn-right") | |
| # Angular Rotated Action Tray | |
| with gr.Row(elem_id="action-container"): | |
| b_b = gr.Button("", elem_id="btn-b") | |
| b_a = gr.Button("", elem_id="btn-a") | |
| gr.HTML('<div class="action-labels"><span>B</span><span>A</span></div>') | |
| # Lower Auxiliary Controls and Speaker Frame | |
| with gr.Row(elem_id="bottom-section"): | |
| with gr.Column(elem_id="start-sel-container"): | |
| b_sel = gr.Button("", elem_id="btn-select") | |
| b_start = gr.Button("", elem_id="btn-start") | |
| gr.HTML('<div class="start-sel-labels"><span>SELECT</span><span>START</span></div>') | |
| gr.HTML(""" | |
| <div id="speaker-container"> | |
| <div class="speaker-slit"></div><div class="speaker-slit"></div> | |
| <div class="speaker-slit"></div><div class="speaker-slit"></div> | |
| <div class="speaker-slit"></div><div class="speaker-slit"></div> | |
| </div> | |
| """) | |
| # Live Neural Trace Panel Output | |
| trace_box = gr.Textbox( | |
| value="[SYSTEM STATUS: STANDBY]\nSelect 'Power On' to trace running tensor weights...", | |
| lines=12, | |
| label="⚡ Live Model Runtime & Register Matrix Trace", | |
| elem_id="model-trace-box", | |
| interactive=False | |
| ) | |
| gr.Markdown("---") | |
| with gr.Accordion("What you are looking at — the full write-up", open=True): | |
| gr.Markdown(WRITEUP) | |
| on_btn.click(power_on, state, [state, scr, status, trace_box, play_timer]) | |
| for btn, key in [(b_up, "up"), (b_down, "down"), (b_left, "left"), (b_right, "right"), | |
| (b_a, "a"), (b_b, "b"), (b_start, "start"), (b_sel, "select")]: | |
| btn.click(gb_enqueue, [state, gr.State(key)], state) | |
| b_wait.click(gb_pause, state, [state, status]) | |
| play_timer.tick(gb_tick, state, [state, scr, status, trace_box]) | |
| v_btn.click(verify_neural, state, [scr, status, trace_box]) | |
| demo.launch() |