Adaptations from the software-rendering playbook, at MRPCI's level of the stack: - pic.rs: fBm noise fill, jittered Voronoi fill (with mortar edges) and scatter — seeded, deterministic, Bayer-dithered through palette ramps - particles.rs: rain/snow/embers layer on its own RNG stream; RoomDoc gains `weather`; visuals can never perturb gameplay replays - font.rs: built-in 5x7 font stamped in index space; headless frames are now annotated (room chip, score, dialogue windows, transcript strip) so MCP render_frame shows what a player actually reads (--raw to skip) - render.rs: compose split into index-space compositing + palette blit; effective_palette() exports the cycle-LUT-applied strip - GUI: frame ships to the GPU as indices + a 256x1 palette texture; a fragment shader does the lookup plus CRT curvature/scanlines/vignette and room-change fades - Neon Precinct: fBm night sky + stars, Voronoi sidewalk & wet cobbles, fBm asphalt, rain in Neon Row and Rain Alley Verified: replay determinism (byte-identical events x2), 25/25 win path, GUI boots with the shader. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| docs | ||
| games/neon-precinct | ||
| mrpci | ||
| mrpci-core | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| README.md | ||
| run.sh | ||
MRPCI — Monster Robot Party Creative Interpreter
The SCI generation of the Monster Robot Party engine family. Where MRPGI reimagines Sierra's 1980s AGI (16 colors, text parser, one merged priority buffer), MRPCI reimagines the tech behind King's Quest V and Space Quest IV — and then fixes everything Sierra never could:
| Sierra SCI (1990) | MRPCI (now) |
|---|---|
| 256-color VGA, hand-cut palettes | 256-color palettes quantized live from any PNG (median cut), EGA/gray/ember ranges kept stable for sprites & cycles |
| Palette cycling (waterfalls, neon) | Same trick, cycles are room data + script-toggleable |
| Priority + control screens | Four screens: visual / priority / control / hotspot — hit-testing any pixel is one array read |
| Polygon avoidance that wedged egos into corners | Real A* with LOS-verified edges + string-pulling; actors walk the exact verified line, so a legal path can never clip |
| Scale tables (SCI1.1) | Per-room perspective: actors shrink toward the horizon, walk speed scales to match |
| CPU-speed timers → Error 52, instant Sequel Police | Fixed 30Hz deterministic cycles; after() timers count ticks; the only RNG is seeded xorshift — replays are byte-identical |
Error 47: Not an object → crash to DOS |
Missing resources = placeholders + an error event. A compile-error script = a log line, not a hang |
| Die 3 hours after the dead-end | Checkpoint at every room entry; death rewinds to it. Save-anywhere slots on top |
| OOP bytecode scripts, priest-tier tooling | rhai room scripts: on_enter, on_verb(v,n), on_trigger, after(ticks,"fn") — hot-swappable over the bus |
| Icon bar (SCI1) or parser (SCI0) | Both. Clicks and typed commands converge on one verb pipeline |
The architecture is inherited from MRPGI and kept sacred: mrpci-core is
headless (zero windowing deps — a compile error is the guardrail). The
whole sim is a GameState behind a typed Command/Event bus, and every
control surface — GUI, JSONL stdio, HTTP, MCP — is a thin adapter.
Run it
cargo run -p mrpci-core --bin mrpci-headless -- --sample # write the demo game
cargo run -p mrpci # play Neon Precinct
Neon Precinct: you are Officer Morp-9. Rain, neon that actually cycles, a vend-bot with a tip, a keycard behind crates (watch the A* go around), a lethal fusebox (watch death not ruin your evening), and a case to close. 25 points.
Controls: left-click applies the verb, right-click cycles verbs, F1–F4 pick
one, I inventory, Enter types a command (the parser is always alive),
F5/F7 save/restore, F9 new game, M mute, N scanlines.
Drive it headless (the point)
cargo build -p mrpci-core
target/debug/mrpci-headless --game games/neon-precinct # JSONL stdio
target/debug/mrpci-headless --game games/neon-precinct --serve 8093 # HTTP
target/debug/mrpci-headless --game games/neon-precinct --mcp # MCP for Claude
target/debug/mrpci-headless --game games/neon-precinct --script play.jsonl # golden replay
target/debug/mrpci-headless --game games/neon-precinct --room 2 --ticks 45 --render-room out.png
target/debug/mrpci-headless --game games/neon-precinct --screens shots/ # all four screens
Register with Claude:
claude mcp add mrpci -- $PWD/target/debug/mrpci-headless --mcp --game $PWD/games/neon-precinct
Claude can then play the game (verbs, walks, dialogue), see it
(mrpci_render_frame, plus the invisible priority/control/hotspot screens),
and author it (upsert rooms and rhai scripts live, validated before commit).
See docs/CONTROL.md for the full bus reference.
A game is a folder
games/mygame/
game.json # manifest: name, start_room, intro, verbs, flags, max_score
rooms/room0.json # RoomDoc: ops (paint), background, palette, cycles, scale,
# spawn, exits, hotspots, props, npcs, music, script
pics/street.png # optional backgrounds (+ street-pri.png / street-ctl.png masks)
sprites/*.png # quantized per-room; filename = sprite name
scripts/*.rhai # main.rhai + room scripts
sfx/ music/ # optional audio overrides (else the built-in chip synth plays)
saves/ # save-anywhere slots (gitignored)
Rooms paint with PicOps — rects, polygons, floods, dithered gradients,
plus procedural fills: fBm noise (clouds, asphalt, grime), Voronoi
cells (cobbles, slabs) and scatter (stars, glints) — all seeded, all
deterministic — through an Ink that writes any subset of the four screens
at once. Or drop a PNG in pics/ and let the quantizer fold it into the
palette. Rooms can also set weather (rain / snow / embers): a particle
layer on its own RNG stream, so visuals never perturb gameplay replays.
Source map
| Crate / file | Role |
|---|---|
mrpci-core/screens.rs |
the four aligned screens + depth bands |
mrpci-core/palette.rs |
256-color palettes, cycling LUTs |
mrpci-core/pic.rs |
vector paint ops, Bayer-dithered gradients |
mrpci-core/assets.rs |
median-cut quantizer, masks, sprite pipeline |
mrpci-core/view.rs |
loops/cels, ASCII sprites, mirroring |
mrpci-core/actor.rs |
ego + NPCs: scaling, line-exact path following |
mrpci-core/path.rs |
A*, LOS smoothing, walk_line |
mrpci-core/room.rs |
RoomDoc / World / game folders / validation |
mrpci-core/script.rs |
rhai host: hooks, Fx airlock, tick timers |
mrpci-core/state.rs |
the bus: GameState, Command/Event, checkpoints |
mrpci-core/render.rs |
headless compositing → RGBA/PNG |
mrpci-core/audio.rs |
multi-voice chip synth (square/pulse/tri/noise) |
mrpci-core/bin/mrpci-headless/ |
stdio / HTTP / MCP / replay / sample |
mrpci/ |
the macroquad GUI (icon bar, dialogue windows, sound) |
Headless frames are annotated: --render-room, HTTP /frame.png and
MCP mrpci_render_frame stamp the room name, score, open dialogue window
and transcript strip into the frame with the built-in 5x7 font — an LLM
sees exactly what a player reads (add --raw / /frame-raw.png to skip).
The GUI renders via a GPU palette shader: the frame ships to the card
as indices + a 256x1 palette strip, and the fragment shader does the lookup
plus the whole CRT (curvature, scanlines, vignette, room fades).
Roadmap
- v0.1 — the engine above + Neon Precinct
- v0.2 — procedural fills (fBm/Voronoi/scatter), weather particles, in-core font + annotated frames, GPU palette/CRT shader
- Priority-mask art workflow polish (paint depth in any image editor)
- In-engine room editor (MRPGI's, upgraded to four screens)
- AI parser lane (LLM maps free text onto already-legal commands, like MRPGI)
- Portraits/talkers in dialogue windows
- wasm build (
mrpci-coreis already windowless — the web is an adapter away)