neural-n64 / app.py
Quazim0t0's picture
Revert to MegaTextures-only showcase (remove Junk Runner switcher + on-screen controller)
1b001eb verified
Raw
History Blame Contribute Delete
27.5 kB
"""Neural N64 -- Gradio Space (private). A Nintendo 64 whose CPU, FPU, RSP
vector unit, and RDP datapath are verified-exact neural units. Run krom's real
hardware-test ROMs live, read the Portal 64 bring-up story, and -- starting from
an in-game snapshot -- actually walk around Test Chamber 00 on the neural N64."""
import os, time, gc
import numpy as np
import gradio as gr
from PIL import Image
from huggingface_hub import snapshot_download
ASSETS = snapshot_download("Quazim0t0/neural-n64",
token=os.environ.get("HF_TOKEN"))
import mips_units
mips_units.CACHE = os.path.join(ASSETS, "models")
import rsp_units, rdp_units # noqa
from n64_console import Console
from snapshot_io import load_state
HERE = os.path.dirname(os.path.abspath(__file__))
PORTAL_ROM = os.path.join(ASSETS, "roms", "portal64.z64") # kept for the bring-up story
PLAY_STATE = os.path.join(ASSETS, "portal_play.state")
GAME_ROM = os.path.join(ASSETS, "roms", "megatextures.z64") # the live playable game
# ===================== krom hardware-test ROMs =====================
TESTS = {
"CPU: ADD/ADDI (krom hardware test)": "CPUADD.N64",
"CPU 64-bit: DADD/DADDI": "CPUDADD.N64",
"FPU: all 10 CVT directions": "CP1CVT.N64",
"FPU: SQRT": "CP1SQRT.N64",
"RSP vector: VMULF (Q15 multiply)": "RSPCP2VMULF.N64",
"RSP vector: VRCP (the silicon ROM table)": "RSPCP2VRCP.N64",
"RDP: shaded triangles": "rdp/ShadeTri.N64",
}
def run_test(name, progress=gr.Progress()):
rom = os.path.join(ASSETS, "roms", TESTS[name])
con = Console(rom)
t0 = time.time()
budget = 3_000_000
while con.cpu.instr_count < budget:
con.cpu.step()
if con.cpu.instr_count % 100_000 == 0:
progress(con.cpu.instr_count / budget,
desc=f"{con.cpu.instr_count:,} MIPS instructions executed")
fb = con.bus.framebuffer()
img = Image.fromarray(fb) if fb is not None else None
return img, (f"**{con.cpu.instr_count:,} instructions** executed by the "
f"neural-methodology R4300i in {time.time()-t0:.0f}s. Every green "
f"PASS was computed by exhaustively-verified units and matches real "
f"N64 hardware.")
# ===================== playable Portal 64 (from snapshot) =====================
# The full boot (BIOS -> menu -> load Test Chamber 00) is ~17 minutes of pure-
# Python neural emulation, so we ship a saved machine state captured just inside
# the chamber (player already controllable) and resume from it in a few seconds.
# N64 controller word: buttons<<16 | (stickX&0xFF)<<8 | (stickY&0xFF), signed sticks.
# Button bits (already shifted into the 32-bit word):
BTN = {
"A": 0x80000000, "B": 0x40000000, "Z": 0x20000000,
"START": 0x10000000, "L": 0x00200000, "R": 0x00100000,
"CU": 0x00080000, "CD": 0x00040000, "CL": 0x00020000, "CR": 0x00010000,
}
# Live controller state. Native Gradio buttons enqueue a key "held" for a few
# ticks (exactly the proven GB/DOOM shell pattern) -- a tap is guaranteed to be
# applied for several frames, then auto-released. A module global (not Gradio
# State) so the continuously-firing play timer can't clobber it (Timer/State
# race). Private/single-user Space, so a global is safe.
_DOWN = {} # key -> ticks remaining held
N64_HELD_TICKS = 3 # face/C buttons: a tap stays pressed this many ticks
N64_MOVE_TICKS = 4 # move/turn: held a touch longer so a tap travels
# Movement keys map to full analog-stick deflection while held (sx=turn, sy=fwd/back).
_MOVE = {"FWD": (0, 90), "BACK": (0, -90), "LEFT": (-90, 0), "RIGHT": (90, 0)}
def n64_press(key):
"""A native button was clicked: arm that key held for the next few ticks."""
_DOWN[key] = N64_MOVE_TICKS if key in _MOVE else N64_HELD_TICKS
return None
def _held_word():
btn = sx = sy = 0
for k in _DOWN:
if k in BTN:
btn |= BTN[k]
elif k in _MOVE:
mx, my = _MOVE[k]
if mx: sx = mx
if my: sy = my
return (btn | ((sx & 0xFF) << 8) | (sy & 0xFF)) & 0xFFFFFFFF
def _age_held():
for k in list(_DOWN):
_DOWN[k] -= 1
if _DOWN[k] <= 0:
del _DOWN[k]
def _rdp_of(con):
return con.bus.rdp if hasattr(con.bus, "rdp") else \
next(o for o in gc.get_objects() if type(o).__name__ == "RDP")
_LATCH = None # FrameLatch: shows only COMPLETE frames (set on power-on)
def _raw_image(con):
"""Decode the buffer the RDP is currently drawing into (may be mid-build)."""
rdp = _rdp_of(con)
org = rdp.color_image & 0x7FFFFF
w = (con.bus.vi.get(8, 320) & 0xFFF) or 320
raw = bytes(con.bus.rdram[org:org + w * 240 * 2]).ljust(w * 240 * 2, b"\0")
a = np.frombuffer(raw, ">u2").reshape(240, w)
r5 = (a >> 11) & 31; g5 = (a >> 6) & 31; b5 = (a >> 1) & 31
return Image.fromarray(np.stack([(r5 << 3) | (r5 >> 2), (g5 << 3) | (g5 >> 2),
(b5 << 3) | (b5 >> 2)], -1).astype(np.uint8))
def _ci_image(con):
"""The frame to DISPLAY: the last COMPLETE (full_synced) scene if we have
one, else the raw current buffer. Portal builds a frame across many emulator
sub-frames, so the raw buffer is usually half-drawn; the latch fixes that."""
if _LATCH is not None:
img = _LATCH.latest()
if img is not None:
return Image.fromarray(img)
return _raw_image(con)
def _vi_image(con):
"""Display the VI front buffer -- correct for cleanly double-buffered games
(e.g. MegaTextures): the VI origin + its real width/height always points at a
COMPLETE displayed frame, so no latch/half-build handling is needed."""
fb = con.bus.framebuffer()
return Image.fromarray(fb) if fb is not None else _raw_image(con)
try:
from n64_cfast import CMachineN64
_CCORES = True
except Exception as _e: # cross-compiled .so failed to load on this host
CMachineN64 = None
_CCORES = False
BOOT_FRAMES = 1400 # power-on -> main menu
# Each timer tick MUST finish under the timer interval (0.3s) or the single HF
# worker backs up and the Space freezes -- that was the bug (old budget 0.5-0.8s
# > 0.3s interval). With the FPU in C (~100x faster) we run as many frames as
# fit in TICK_BUDGET (strictly < the interval, so no backup) up to a frame cap.
# Fast host -> hits the cap; slow host -> stops at the budget. Either way the
# handler always returns in time and stays responsive.
PLAY_TIMER = 0.1 # play/boot tick interval (s)
TICK_BUDGET = 0.085 # wall seconds/tick, strictly under PLAY_TIMER (no backup)
BOOT_FRAMES_PER_TICK = 200 # cap; boot is ~1400 frames (runs to budget)
LOAD_FRAMES_PER_TICK = 200 # cap; chamber load is ~1150 black frames (runs to budget)
LOAD_FRAMES_MAX = 2400 # hard cap: never fast-forward forever
PLAY_TARGET_FRAMES = 6 # game-frames per tick (bails at TICK_BUDGET)
PLAY_IPL = 3500 # CPU instr/scanline in gameplay (~1 real frame of CPU
# per VI period) so the game finishes drawing before it
# swaps -- the fix for the near-black in-game display.
def n64_power(state):
global _LATCH
if _CCORES:
try:
mach = CMachineN64(GAME_ROM) # both C cores drive it
_LATCH = None # double-buffers cleanly: show VI buf
st = {"mach": mach, "con": mach.con, "pymode": False, "megatx": True,
"phase": "play", "frame": 0, "down": {}, "paused": False,
"trace": {"rdp_cmds": 0, "tris": 0}}
_attach_trace(st) # count neural RDP work live
w0 = time.time() # warm up past the initial texture
for _ in range(160): # stream to the first stable scene
mach.run_frame(instr_per_line=PLAY_IPL); st["frame"] += 1
fb = mach.con.bus.framebuffer()
if fb is not None and float((fb.sum(-1) > 40).mean()) > 0.1:
st["last_img"] = Image.fromarray(fb)
if time.time() - w0 > 8:
break
first = st.get("last_img") or _vi_image(mach.con)
return (st, first,
"โป Powered on the neural N64 โ€” **MegaTextures** is rendering its "
"streamed-texture 3D scene live, entirely on neural-network logic.",
_trace_md(st), gr.Timer(PLAY_TIMER, active=True))
except Exception:
pass
# fallback: cold-boot on the pure-Python neural core (slow, but needs no .so)
con = Console(GAME_ROM)
st = {"mach": None, "con": con, "pymode": True, "megatx": True,
"phase": "play", "frame": 0, "down": {}, "paused": False,
"trace": {"rdp_cmds": 0, "tris": 0}}
return (st, _vi_image(con),
"โ–ถ Cold-booting MegaTextures on the pure-Python neural core (C cores "
"unavailable here) โ€” slow, but every pixel is neural.",
_trace_md(st), gr.Timer(PLAY_TIMER, active=True))
def _advance(st, ipl=60):
# ipl = CPU instructions per VI scanline. Boot/load run lean (60) to fast-
# forward. Gameplay MUST run a realistic ratio (~a full game-frame of CPU per
# VI period) or the game swaps near-empty buffers to the display -- at 60 the
# shown buffer is ~2% lit (looks black); at ~3500 it builds a real frame.
if st["pymode"]: st["con"].run_frames(1, instr_per_line=ipl)
else: st["mach"].run_frame(instr_per_line=ipl)
def _attach_trace(state):
"""Wrap the RDP entry so the live trace can count the neural pixel-pipeline
work (commands + triangles) as the scene renders."""
con = state["con"]; tr = state["trace"]
orig = con.bus.rdp.run
def traced(words, _o=orig, _t=tr):
_t["rdp_cmds"] += len(words)
for w in words:
if 0x08 <= ((int(w) >> 56) & 0x3F) <= 0x0F:
_t["tris"] += 1
return _o(words)
con.bus.rdp.run = traced
def _trace_md(state):
"""A live readout of what the neural machine is computing right now."""
tr = state.get("trace", {})
instr = (state["con"].cpu.instr_count if state.get("pymode")
else int(state["mach"].ms.instr_count))
return (
"#### ๐Ÿง  Live neural-execution trace\n"
"*Every number below was produced by exhaustively-verified neural networks โ€” "
"not hand-written emulator code.*\n\n"
f"- **R4300i CPU** โ€” neural ALU / shifter / decoder: **{instr:,}** instructions executed\n"
f"- **RDP rasterizer** โ€” neural pixel pipeline: **{tr.get('rdp_cmds',0):,}** "
f"commands ยท **{tr.get('tris',0):,}** triangles\n"
f"- **Frame {state.get('frame',0)}** ยท scene **{state.get('lit',0.0):.0%}** textured "
"(MegaTextures streams its textures in over the first seconds)")
def _run_megatx(state, n):
"""Advance up to n game-frames and return the MOST-LIT VI front buffer seen.
MegaTextures double-buffers, so any single sample can catch the buffer
mid-clear (black); picking the most-lit frame in the tick always yields a
complete scene (the VI-buffer analog of the latch)."""
con = state["con"]; word = _held_word()
t0 = time.time(); best = None; bestlit = -1.0
for i in range(n):
if i and time.time() - t0 >= TICK_BUDGET:
break
con.bus.buttons = word
_advance(state, ipl=PLAY_IPL); state["frame"] = state.get("frame", 0) + 1
fb = con.bus.framebuffer()
if fb is not None:
lit = float((fb.sum(-1) > 40).mean())
if lit > bestlit:
bestlit = lit; best = fb
# MegaTextures streams textures: between scenes the buffer is briefly black.
# Keep the last complete scene and hold it during those stretches (no flicker).
if best is not None and bestlit > 0.1:
state["last_img"] = Image.fromarray(best); state["lit"] = bestlit
return state.get("last_img") or (Image.fromarray(best) if best is not None
else _vi_image(con))
def n64_pause(state):
if not state or not state.get("con"):
return state, "Press โป Power On first."
state["paused"] = not state.get("paused", False)
return state, ("โธ paused" if state["paused"] else "โ–ถ running live")
def n64_tick(state):
# Showcase: keep advancing the neural machine, display the latest complete
# scene, and refresh the live execution trace. (MegaTextures renders its
# scene but doesn't run a sustained interactive loop, so there's no input.)
if not state or not state.get("con") or state.get("paused"):
return state, gr.update(), gr.update(), gr.update()
img = _run_megatx(state, PLAY_TARGET_FRAMES)
return state, img, gr.update(), _trace_md(state)
def _dead_tick_unused(state): # (former Portal boot/menu/chamber flow; kept out of the live path)
con = state["con"]
if state["phase"] == "boot":
t0 = time.time()
for _ in range(BOOT_FRAMES_PER_TICK):
if state["frame"] >= BOOT_FRAMES or time.time() - t0 >= TICK_BUDGET:
break
con.bus.buttons = 0
_advance(state); state["frame"] += 1
if state["frame"] >= BOOT_FRAMES:
state["phase"] = "play"
return state, _ci_image(con), "โ–ถ menu"
return state, _ci_image(con), f"โป bootingโ€ฆ frame {state['frame']}/{BOOT_FRAMES}"
is_black = int((np.asarray(_raw_image(con)).sum(-1) > 40).sum()) < 2000
state["load"] = state.get("load", 0)
if is_black and state["load"] < LOAD_FRAMES_MAX:
t0 = time.time()
for _ in range(LOAD_FRAMES_PER_TICK):
if time.time() - t0 >= TICK_BUDGET:
break
con.bus.buttons = 0; _advance(state); state["load"] += 1
if int((np.asarray(_raw_image(con)).sum(-1) > 40).sum()) >= 2000:
break
return state, _ci_image(con), (f"โณ Loading test chamberโ€ฆ ({state['load']} "
"frames; every pixel is neural)")
# interactive play: apply the live on-screen controller each frame, paced to
# real-time (PLAY_TARGET_FRAMES at the tick rate) but bailing at TICK_BUDGET.
word = _held_word()
t0 = time.time()
for i in range(PLAY_TARGET_FRAMES):
if i and time.time() - t0 >= TICK_BUDGET:
break
con.bus.buttons = word
_advance(state, ipl=PLAY_IPL) # realistic ratio -> real frames
_age_held() # age the held keys one tick
return state, _ci_image(con), gr.update()
# ===================== UI =====================
CSS = """
:root { color-scheme: dark; }
body, .gradio-container { background:
radial-gradient(ellipse at 20% -10%, #0a1a2e 0%, #0a0a14 45%, #050508 100%) !important; }
#hero h1 { font-size: 2.5em; font-weight: 900;
background: linear-gradient(90deg, #2a6df5, #38c172, #f5d52a, #e23b3b);
background-size: 300% 100%; -webkit-background-clip: text;
background-clip: text; color: transparent; animation: chroma 8s linear infinite; }
@keyframes chroma { to { background-position: 300% 50%; } }
.panel { border-radius: 14px; padding: 6px; background:
linear-gradient(#0e0e1a,#0e0e1a) padding-box,
linear-gradient(135deg,#2a6df566,#38c17266,#e23b3b66) border-box;
border: 1px solid transparent; }
button.primary, .primary {
background: linear-gradient(90deg, #2a6df5, #38c172) !important;
border: none !important; color: #fff !important; font-weight: 700 !important; }
#n64screen { position: relative; border-radius: 10px; overflow: hidden; background:#000;
box-shadow: 0 0 30px #2a6df533, inset 0 0 60px #000a;
max-width: 860px; margin: 0 auto; padding: 0 !important; } /* ~2.7x native frame */
/* Force the whole Gradio image wrapper chain to fill, not just the <img>. */
#n64screen .image-container, #n64screen .image-frame,
#n64screen .image-button, #n64screen > div { width: 100% !important;
height: 100% !important; max-width: 100% !important; padding: 0 !important; }
#n64screen img { image-rendering: pixelated; width: 100% !important;
height: auto !important; max-width: 100% !important; object-fit: contain;
display: block; margin: 0 auto; }
/* ---- on-screen N64 controller: native Gradio buttons (no JS bridge) ---- */
#n64pad { gap:22px !important; padding:16px; margin:12px auto 2px; max-width:680px;
border-radius:18px; background:linear-gradient(145deg,#16161f,#0b0b12);
box-shadow:inset 0 0 44px #0009, 0 6px 22px #0007; justify-content:center; }
.padcol { min-width:150px; max-width:200px; align-items:center; }
.padcol .md, .padcol p { text-align:center; color:#8ea0c0;
font:700 11px system-ui !important; letter-spacing:.10em; margin:0 0 2px; }
#n64pad button { border:none !important; border-radius:11px !important;
font:800 14px system-ui !important; color:#fff !important; min-width:0 !important;
box-shadow:0 4px 0 #0006 !important; transition:filter .05s, transform .05s; }
#n64pad button:active { transform:translateY(2px); filter:brightness(1.35); }
.nbtn.move button, button.nbtn.move { background:#3a4a66 !important; }
.nbtn.a button, button.nbtn.a { background:#2bb24b !important; }
.nbtn.b button, button.nbtn.b { background:#2a6df5 !important; }
.nbtn.z button, button.nbtn.z { background:#6b3fb5 !important; }
.nbtn.l button, .nbtn.r button, button.nbtn.l, button.nbtn.r { background:#4a4a5a !important; }
.nbtn.start button, button.nbtn.start { background:#c0392b !important; }
.nbtn.c button, button.nbtn.c { background:#b58b00 !important; }
/* ---- live neural-execution trace readout ---- */
#trace { background:#0a0e18; border:1px solid #1d2740; border-radius:12px;
padding:6px 18px; margin-top:10px; box-shadow:inset 0 0 30px #0006; }
#trace, #trace * { font-family: ui-monospace, "SF Mono", Menlo, monospace !important;
color:#9fd0ff; }
#trace strong { color:#eaf4ff !important; }
"""
# Page-load JS: only force the dark theme (the controller is now native buttons).
APP_JS = r"""
() => { try { const u = new URL(window.location);
if (u.searchParams.get('__theme') !== 'dark') {
u.searchParams.set('__theme','dark'); window.location.href = u.href; } } catch(e){} }
"""
def gallery_image(fname, cap):
p = os.path.join(HERE, fname)
if os.path.exists(p):
return gr.Image(value=Image.open(p), label=cap, interactive=False)
return None
with gr.Blocks(title="Neural N64") as demo:
with gr.Column(elem_id="hero"):
gr.Markdown(
"# NEURAL N64\n"
"### A Nintendo 64 whose logic is neural networks โ€” verified against real hardware\n"
"The R4300i CPU, the IEEE-754 FPU, the RSP vector unit (including the "
"console's silicon reciprocal ROM, reborn as a 512-case verified net), and "
"the RDP rasterizer โ€” every unit trained on its complete input domain, exact "
"at N-of-N, validated by QEMU fuzzing and krom's hardware test ROMs. "
"It boots and **plays real N64 homebrew** โ€” live, in your browser.")
gr.Markdown(
"### ๐Ÿ™ Homebrew by James Lambert\n"
"**MegaTextures**, **Junk Runner 64**, and **Portal 64** are all the work of "
"**James Lambert** ([github.com/lambertjamesd](https://github.com/lambertjamesd), "
"[YouTube](https://www.youtube.com/@JamesLambertGames)). This Space exists "
"because of his homebrew โ€” none of this work could be shown publicly without "
"his open N64 projects. **Thank you, James.**")
# ---- PLAY ----
with gr.Column(elem_classes="panel"):
gr.Markdown(
"## ๐ŸŽฎ MegaTextures โ€” rendered live on the neural N64\n"
"Press **โป Power On** and the neural N64 boots **MegaTextures** (a libultra "
"homebrew 3D demo by **James Lambert**) and renders its streamed-texture chapel "
"scene in a few seconds โ€” **every pixel produced by neural-network logic.** A C "
"orchestrator drives the **R4300i CPU, the RSP vector unit, and the RDP "
"rasterizer**, all bit-identical to the verified neural cores (only the I/O bus "
"stays in Python). Watch the **live execution trace** below count the neural "
"work as the scene streams in.")
play_state = gr.State(None)
play_timer = gr.Timer(PLAY_TIMER, active=False)
with gr.Group(elem_id="n64screen"):
play_scr = gr.Image(type="pil", show_label=False, interactive=False)
play_status = gr.Markdown("Press โป Power On to boot MegaTextures.")
with gr.Row():
e_btn = gr.Button("โป Power On", variant="primary")
b_pause = gr.Button("โธ pause / resume")
play_trace = gr.Markdown("", elem_id="trace")
e_btn.click(n64_power, play_state,
[play_state, play_scr, play_status, play_trace, play_timer])
b_pause.click(n64_pause, play_state, [play_state, play_status])
play_timer.tick(n64_tick, play_state,
[play_state, play_scr, play_status, play_trace])
# ---- how the neural networks are used ----
with gr.Column(elem_classes="panel"):
gr.Markdown(
"## ๐Ÿง  Where are the neural networks?\n"
"This isn't an emulator with an ML feature bolted on โ€” **the console's logic "
"itself is neural networks.** Every arithmetic & logic operation the N64 "
"performs is computed by a small trained network, verified to reproduce the "
"exact hardware result **at N-of-N** (every possible input checked) before it's "
"allowed in:\n\n"
"- **R4300i CPU** โ€” the integer datapath is composed from verified neural "
"*slice* nets: an 8-bit add-with-carry net (`ADD8C`), logic-gate nets "
"(`AND8/OR8/XOR8/NOR8`), a 1-bit shift net, and partial-product nets for "
"multiply. 32- and 64-bit add / sub / shift / multiply are built by **wiring "
"these verified slices together** and rippling carries โ€” the wide ops are exact "
"because every slice is exact.\n"
"- **FPU (COP1)** โ€” the IEEE-754 datapath (convert / round / compare) realized "
"the same slice-and-verify way.\n"
"- **RSP vector unit** โ€” the SIMD lanes, including the N64's **silicon "
"reciprocal / inverse-sqrt ROM reborn as a single 512-case verified net.**\n"
"- **Instruction decode** โ€” opcode / funct / regimm are three tiny enumerable "
"tables learned as classifier nets.\n\n"
"Each net is trained on its **entire** input domain and kept only if it scores "
"100% against the truth table; correctness is then cross-checked with QEMU "
"fuzzing and **krom's real-hardware test ROMs** (run them yourself below). For a "
"responsive public demo the live run takes native fast paths **proven "
"bit-identical** to the verified nets โ€” so what you see is exactly what the "
"neural units compute, just fast enough to render in real time.")
# ---- the journey ----
with gr.Column(elem_classes="panel"):
gr.Markdown(
"## ๐ŸŒ€ How a fully-neural N64 ended up running Portal\n"
"Portal 64 is a real fan-made demake by James Lambert, built on Nintendo's "
"libultra SDK. Getting it from a black screen to a walkable test chamber on "
"a machine made of neural nets took a long chain of exact fixes โ€” every bug "
"was in the *wiring* (tables, masks, timing), never in a verified unit:\n\n"
"1. **libultra boots.** The OS came alive once two gates were satisfied โ€” "
"the `osMemSize` Expansion-Pak check (HLE boot writes 8 MB to 0x318/0x3F0) "
"and GCC's `TEQ` divide-guards as real trapping instructions.\n"
"2. **The frame loop runs.** Cause.IP2โ€“7 had to be *live* interrupt lines "
"(not latched), MTC0-to-Compare must ack the timer, and `MI_MODE` must clear "
"the DP interrupt โ€” otherwise the idle thread spins forever.\n"
"3. **The RSP wakes up.** At ~frame 564 the game DMAs Nintendo's F3DEX2 "
"microcode into the RSP, which runs it on the verified vector unit with "
"**zero errors**. RSPโ†’RDP commands flow over the XBUS FIFO; the CPU pumps it.\n"
"4. **Pixels.** The RDP grew a TMEM + texture pipeline (LOAD_TILE/BLOCK with "
"odd-line swizzle, RGBA16/IA/CI formats, per-tile clamp/mirror/mask, "
"perspective-correct triangles with a Z-buffer). The Valve intro, then the "
"3D menu chamber, rendered clean.\n"
"5. **The menu text.** The menu drew its glyphs as **IA4 texrects** whose "
"shape lives in the *alpha* channel; we were writing white-on-white. Adding "
"the combiner's alpha output + a 1-cycle alpha-blend made `PORTAL / NEW GAME "
"/ LOAD GAME / OPTIONS` legible.\n"
"6. **Loading in.** Start skips the intro, A picks NEW GAME, A confirms "
"Testchamber 00 โ€” then the level loads (~1650 frames of DMA + scene build) "
"and the first-person chamber renders. The player becomes controllable ~180 "
"frames later; the stick then drives the camera. **We're in the game.**\n"
"7. **Speed.** Native fast paths for the hot RSP vector ops (proven "
"bit-identical to the verified slices over 250k cases) gave the multiply-"
"heavy frames up to a 25ร— speedup โ€” enough to make all of the above "
"iterable, and this very Space possible.")
# ---- gallery ----
gr.Markdown("### What it looks like")
with gr.Row():
gallery_image("portal_game_menu.png", "Main menu (text now renders)")
gallery_image("portal_game_chapter.png", "Chapter select โ€” Testchamber 00")
with gr.Row():
gallery_image("portal_ingame_play.png", "In-game: the test-chamber floor")
gallery_image("portal_ingame_corner.png", "In-game: white-panel corner")
# ---- krom hardware tests ----
with gr.Column(elem_classes="panel"):
gr.Markdown("## ๐ŸŽ› Run a real N64 hardware test, live\n"
"These ROMs were written by the emulator community to validate "
"against real consoles. They run here on the neural machine and draw "
"their own PASS/FAIL verdicts.")
sel = gr.Dropdown(list(TESTS), value=list(TESTS)[0], label="test ROM",
filterable=False)
btn = gr.Button("โšก Run on the neural N64", variant="primary")
out_img = gr.Image(type="pil", show_label=False, interactive=False)
out_md = gr.Markdown()
btn.click(run_test, sel, [out_img, out_md])
with gr.Row():
for f, cap in (("krom_add.png", "CPU tests"), ("krom_cp1_cvt.png", "FPU CVT"),
("krom_rsp_vrcp.png", "RSP reciprocal ROM"),
("rdp_sidebyside.png", "RDP vs hardware capture")):
gallery_image(f, cap)
demo.launch(css=CSS, js=APP_JS)