MRPGI/MANUAL.md
type-two 2fdd730cde Add the updated manual and a teaching game: The DJ's Lost Fuse
- MANUAL.md brought up to the workspace era: game folders + manifest,
  flags & gated puzzles, hidden dialogue choices, audio file
  overrides, a Programmatic control section (CLI/HTTP/MCP/Python),
  and the new two-crate architecture map.
- games/lost-fuse: three rooms that demonstrate every mechanic in one
  chain — item, needs-lock, object sets_flag, a dialogue choice hidden
  behind requires_flag, dialogue sets_flag, and a flag-locked wins
  finale. Verified winnable headlessly, gate included.
- games/lost-fuse/expansion/roof.jsonl: a live lore drop that upserts
  a fourth room into a running game and rewires an exit — the "drop
  JSON lore in" workflow, runnable as a one-liner.
- games/README.md: the guided tour — mechanic-to-JSON map, the live
  expansion demo, and how to prompt an LLM (or point Claude's MCP at
  the engine) to write valid lore.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 09:18:50 +10:00

27 KiB
Raw Permalink Blame History

MRPGI — The Complete Manual

Monster Robot Party Game Interpreter — a new-school, Apple-Silicon-native reimagining of Sierra's 1980s AGI adventure engine, written in Rust + macroquad. You paint rooms, drop in objects, write puzzles, and walk through them — with a text parser, optional local-AI understanding, branching dialogue, chiptune sound, and ambient music. No external level files, no build step beyond cargo.

This manual is exhaustive. Jump around with the table of contents.


Table of contents

  1. What MRPGI is
  2. Install & requirements
  3. Running it
  4. The two modes
  5. Core concepts (read this)
  6. The editor — full reference
  7. Keyboard cheat sheet
  8. Building a world (rooms & exits)
  9. Objects & game logic
  10. The parser
  11. The AI parser lane
  12. Dialogue trees
  13. Sound & music
  14. The art / sprite pipeline
  15. The kit & theme packs
  16. Games as folders & the file formats
  17. Programmatic control (CLI · HTTP · MCP · Python)
  18. Project layout & architecture
  19. Troubleshooting
  20. Roadmap & known gaps

1. What MRPGI is

AGI was the engine behind King's Quest, Space Quest, and Police Quest. Its genius was a dual-buffer model: every room is drawn into a visual screen (what you see) and a hidden priority screen (depth + walkability). MRPGI keeps that soul and modernizes everything around it:

  • In-engine room editor — paint walls, floors, and walkability by hand.
  • Sprite pipeline — drop PNGs in a folder; they're auto-quantized to EGA.
  • Multi-room worlds with edge exits.
  • Objects with descriptions, locks, keys, and win conditions — no code.
  • A forgiving parser + an optional local LLM that understands plain English.
  • Branching dialogue, chiptune SFX, and ambient room music.
  • Flags & gated puzzles — multi-step quests authored as plain JSON.
  • A content kit: 61 click-to-place archetypes across fantasy, sci-fi, monsters, "saucy" nightlife, and classic horror.
  • A fully headless core — the same engine is drivable from the command line, HTTP, Python, or an AI over MCP, with no window (§17).

Everything saves to small, human-readable JSON: a game is a folder you can zip, share, or have an LLM write. The engine builds with cargo into two binaries: the GUI (mrpgi) and the headless multi-tool (mrpgi-headless).


2. Install & requirements

Required:

  • Rust (stable, 1.85+). Install from https://rustup.rs or Homebrew.
  • That's it for building — macroquad pulls its own dependencies and renders natively (Metal on macOS). No system libraries to install.

Optional (for the AI parser):

  • Ollama running locally with a small instruct model (e.g. a Gemma 4B). Free, offline, private. Or an OpenRouter API key.

First build downloads the crate tree and takes a minute or two; subsequent builds are seconds.


3. Running it

cargo run -p mrpgi            # build + run the GUI (dev)
cargo run -p mrpgi --release  # optimized build (smoother), slower first compile
./run.sh                      # convenience launcher that points the AI lane at your model

Launch flags

Flag Effect
(none) Loads the game in the current directory (game.json + rooms/room0.json) and opens in the editor.
--game DIR Load a game folder instead of the current directory (see §16).
--sample Writes a 3-room "escape the party" demo (+ game.json) then runs it (existing rooms backed up to *.json.bak).
--kit Generates the fantasy starter kit + placeholder sprites, and installs a 4-room fantasy world (existing → .bak).
cargo run -p mrpgi -- --kit                       # install + play the fantasy starter world
cargo run -p mrpgi -- --sample                    # install + play the robot escape demo
cargo run -p mrpgi -- --game games/lost-fuse      # play the example game (§16)

The headless binary takes the same --game / --sample / --kit flags:

cargo run -p mrpgi-core --bin mrpgi-headless -- --sample --game games/demo

AI environment variables

Var Default Meaning
MRPGI_AI ollama ollama · openrouter · off
MRPGI_AI_MODEL gemma3:4b the model tag (set to YOUR Ollama tag)
MRPGI_AI_URL http://localhost:11434/api/generate endpoint override
OPENROUTER_API_KEY required when MRPGI_AI=openrouter
MRPGI_AI_MODEL="your-gemma-tag" cargo run
MRPGI_AI=openrouter OPENROUTER_API_KEY=sk-... MRPGI_AI_MODEL=google/gemma-2-9b-it:free cargo run
MRPGI_AI=off cargo run    # deterministic parser only

4. The two modes

MRPGI is always in one of two modes; Tab flips between them:

  • EDIT — the painting/authoring mode. Left panel of tools, a canvas, a top strip for world/room controls. The engine boots here.
  • PLAY — you become the robot. Walk with arrows or click, type commands, talk to NPCs. A bottom panel shows the transcript + command line.

Esc quits (in edit it first un-focuses a text field; in play it first ends a conversation).


5. Core concepts (read this)

The dual buffer — LOOK vs MEANING

Every pixel of a room has two independent properties:

  • LOOK — its colour (one of 16 EGA colours). What the player sees.
  • MEANING — what it is to the engine: walkable floor, a wall, water, a trigger, or a depth band. Stored in a hidden "priority" buffer.

Colour does not imply meaning. A brown floor and a brown wall look identical but behave differently. When you paint, you set a colour and (optionally) a meaning tag; they're applied to the same region but stored separately. This is the single most important idea in MRPGI.

Meaning tags

Tag Effect on the priority buffer
floor walkable, with automatic depth (lower on screen = drawn in front)
wall blocked — the robot can't enter
water reserved (special)
trigger reserved (signal line for future logic)
none paint colour only; leave walkability unchanged

By default an empty room is entirely walkable — you paint walls where you don't want walking.

The picture

The play area is 160 × 168 logical pixels, displayed at a 2:1 pixel ratio (each pixel is twice as wide as tall — classic AGI). Colours are the 16-colour EGA palette (indices 015). A perfect circle drawn in art tools looks slightly wide in-game; that's intentional retro flavour.

EGA palette

0 black · 1 blue · 2 green · 3 cyan · 4 red · 5 magenta · 6 brown · 7 light gray · 8 dark gray · 9 light blue · 10 light green · 11 light cyan · 12 light red · 13 light magenta · 14 yellow · 15 white.

The ego

"Ego" is the AGI term for the player avatar (the little robot). Its position is its feet (bottom-centre of its sprite), which is what determines its depth and collision. In play it's blocked by wall pixels and walks off exit edges.


6. The editor — full reference

The editor screen: a tool panel on the left, the canvas on the right, and a world strip across the top of the canvas.

Tools (number keys, or click in the panel)

Key Tool What it does
1 brush freehand paint with the current colour + meaning (size via , .)
2 line click to add points; right-click or Enter finishes the polyline
3 rect drag a filled rectangle
4 fill flood-fill a sealed region (the bucket) — fast
5 pick eyedropper; grab a colour off the canvas
6 erase rub back to blank + walkable
7 image stamp a sprite from sprites/ ([ ] to choose, R to reload)
8 oval drag a filled ellipse
9 spawn click to set where the robot appears in play (cyan circle)
0 object place a live object — see below

Colour & meaning

  • Palette (left panel): click a swatch to set the current LOOK colour.
  • Meaning buttons: floor / wall / water / trigger / none — the MEANING applied by fills, rects, brush, etc.

View modes (L cycles)

  • look — the plain picture.
  • both — picture + walls tinted red, water blue, triggers green (so you can see what's walkable).
  • ctrl — the raw meaning map (depth + control).

The object tool & kit browser (0)

With the object tool active the panel shows kit [ ]: <name>. Press [ ] to flip through 60+ ready-made archetypes (orc, console, cocktail, coffin…). Click an empty spot to stamp the selected archetype, fully written. Cycle to (blank) to drop a bare object named after the current sprite. Click an existing object to select it; the inspector then shows editable fields:

  • name — what the parser calls it.
  • look text — response to look.
  • use text — response to use/open.
  • needs item — an item required to use it (empty = unlocked).
  • synonyms — extra nouns it answers to (space-separated).
  • takeable / fixed toggle, wins toggle, delete.

Click a field, type, Enter jumps to the next field, Esc finishes.

The world strip (top)

  • room N + < > — move between rooms (also - =). Switching auto-saves.
  • exits N E S W — click to cycle each edge's target room number.
  • — cycle the room's ambient music mood (off · calm · eerie · tense · jolly · spooky).

Saving

  • K saves the current room to rooms/room<N>.json (an editable list of strokes
    • objects + exits + spawn + music). O reloads it. C clears, Z/Backspace undoes. The game auto-loads rooms/room0.json on startup.

7. Keyboard cheat sheet

Global: Tab edit ⇄ play · Esc quit (or un-focus / end conversation) · F1 CRT scanlines · F2 mute sound + music.

Editor: 10 tools · L view · [ ] choose sprite / kit archetype · , . brush size · - = prev / next room · Z/Backspace undo · C clear · K save · O load · R reload sprites + kit.

Play: arrows / click to walk · type a command + Enter · 16 choose a dialogue reply · Esc leave a conversation.


8. Building a world (rooms & exits)

A room is one screen. A world is rooms linked by their edges.

  1. Paint a room. Leave a walkable gap in a wall where you want a doorway.
  2. On the strip, set that edge's exit to a room number (e.g. E: 1).
  3. Press > to go to that room (going past the last room makes a new blank one), paint it, and set a matching exit back.
  4. In play, walk off the edge with an exit → you arrive in the target room, entering from the opposite side.

Rooms are files: rooms/room0.json, room1.json, … Room 0 is where the game starts. The spawn tool sets each room's entry point (used if the edge you arrive at is walled).


9. Objects & game logic

Objects are sprites you can interact with. Each carries:

  • a name + synonyms (what the parser matches),
  • look text (shown on look),
  • use text (shown on use/open),
  • needs — an item that must be in your inventory to use it,
  • wins — using it successfully ends the game with a victory banner,
  • takeable — whether take adds it to your inventory,
  • requires_flag — a flag that must be true before use works,
  • sets_flag — a flag set true when use succeeds.

This is enough for the classic adventure loop with no code:

Put a key (takeable) in one room and a gate in another with needs = key, use text = "The gate grinds open…", wins = on. Now: take key → travel → use gatewin.

Flags — multi-step quests

Flags are named booleans that live for one play session (a game's game.json can preset them). Objects and dialogue choices read and write them:

A lever with sets_flag = power_on. A door with requires_flag = power_on, wins = on. Now use door says "Nothing happens. Something else must come first." until you use lever.

Chain needs (items) with requires_flag/sets_flag (state) and gated dialogue (§12) and you get real multi-step quests — all data, no code. The example game games/lost-fuse/ demonstrates the whole chain (§16).

Taking an object removes it from the room (runtime only — it returns on a fresh play). Objects do not block movement (walls come from the painted meaning layer). Currently requires_flag/sets_flag are JSON-authored (the editor inspector shows the older fields only).


10. The parser

Type a sentence; it's lower-cased, filler words are dropped, the first word maps to a canonical verb, and the rest is the noun (matched against object names + synonyms, loosely).

Verbs (and their synonyms):

  • look — look, l, examine, x, inspect, check, read, view, see, study
  • take — take, get, grab, pick, snatch, steal, pocket, collect, nab
  • use — use, open, unlock, activate, push, pull, turn, operate
  • drop — drop, discard, leave, put
  • talk — talk, speak, ask, chat, greet, say
  • inventory — inventory, inv, i, items, bag
  • help — help, ?, commands, verbs

Ignored filler: the, a, an, at, to, with, on, of, my, your, some, please, go, up.

look with no noun (or look around) lists what's in the room. Unknown verbs fall through to the AI lane (if enabled) or print "I don't understand".


11. The AI parser lane

When the deterministic parser can't recognise your verb, MRPGI can hand the raw sentence to a small LLM, which translates it into one allowed command — then re-runs that through the normal logic. The AI bends the language; your game still decides what's possible. It never invents items or outcomes, and it runs on a background thread so the game never stalls. The chosen command is shown as (≈ open crate).

Setup (local, recommended): run Ollama with an instruct model and point MRPGI at it via MRPGI_AI_MODEL (see §3). Default provider is ollama. If Ollama isn't running or the model is missing, the lane stays silent and you get the normal deterministic behaviour — nothing breaks.

OpenRouter: set MRPGI_AI=openrouter, OPENROUTER_API_KEY, and a MRPGI_AI_MODEL like google/gemma-2-9b-it:free.

The bottom bar shows ai: ollama/<model> (or off).


12. Dialogue trees

An object can carry a branching conversation. In play, talk <name> starts it: the NPC speaks and you press a number key (16) to choose a reply. Choices jump to other lines; some end the chat. Esc leaves. Walking pauses while you talk.

Dialogue is authored as a dialogue array on the object (a visual builder is planned). Each entry is a node; node 0 is the entry. See the inn barkeep in rooms/room3.json for a working example:

"dialogue": [
  { "says": "You're for the cave, aren't you?",
    "choices": [
      { "text": "What's down there?", "goto": 1 },
      { "text": "Just passing through.", "goto": 3 }
    ] },
  { "says": "Orcs. Dark. A spellbook nobody should read aloud.",
    "choices": [ { "text": "Thanks.", "goto": -1 } ] }
]

A choice's goto is the next node index, or -1 to end. A node with no choices is a terminal line (shown, then the conversation ends).

Gated choices

Choices can read and write flags (§9), which makes conversations part of the puzzle chain:

{ "text": "Hear that? I'm with the band.", "goto": 2,
  "requires_flag": "music_on", "sets_flag": "on_the_list" }

A choice with requires_flag is hidden until that flag is true — the numbering the player sees always matches what they can pick. sets_flag fires when the choice is chosen. So an NPC can refuse to say something until you've done a thing, and telling them can unlock a door elsewhere.


13. Sound & music

By default all audio is synthesized at runtime (square waves → PCM, no files), in the spirit of AGI's PCjr beeper — and any of it can be overridden per game with real audio files (below).

SFX (play mode): a blip when you submit a command, a ding on take, a chime on a successful use/look, a buzz when nothing matches, a whoosh on room change, a 4-note fanfare on win.

Ambient music: each room can loop one of five moods (calm / eerie / tense / jolly / spooky), set with the strip button in the editor and saved per room. It plays in play mode and switches as you move between rooms.

F2 mutes music and SFX together. If a machine has no audio backend, everything degrades to silence.

Your own audio files

Drop files into the game folder and they replace the synth, cue for cue:

<game>/sfx/blip|pickup|confirm|error|door|win .wav|.ogg|.mp3
<game>/music/calm|eerie|tense|jolly|spooky .wav|.ogg|.mp3   (or 1.ogg … 5.ogg)

Anything you don't provide keeps its chiptune default. Prefer OGG for looping music (MP3 encoders pad silence that clicks at the loop seam).


14. The art / sprite pipeline

Sprites live in sprites/ as PNGs. On load, any image is quantized to the EGA palette (with transparency from its alpha), so it depth-sorts and walks-behind like native art. Replace any sprite and press R to reload.

The sprite spec:

  • PNG with transparency. Transparent pixels are see-through.
  • Small, at game scale. A prop is ~1228 px tall; draw 1:1.
  • Filename = id. lowercase, no spaces (orc.png). The object's sprite field references this name. A missing sprite shows as a magenta placeholder.
  • Bottom-centre = feet. Stand the thing on the bottom edge of the canvas.
  • EGA colours ideal but not required — load palettes/mrpgi-ega.gpl into Aseprite/Inkscape, or let the engine snap your colours on load.

Aseprite: Palette → Load Palette → palettes/mrpgi-ega.gpl; draw small; export PNG to sprites/; press R.

Inkscape: set a tiny px page; Export PNG (transparent) to sprites/.

AI (Gemini "Nano Banana" / Imagen): each theme's gemini_sprites.md has a shared STYLE line + per-sprite prompts. Generate on a solid magenta background, key it out to transparency, save into sprites/. (See also palettes/mrpgi-ega.gpl and palettes/mrpgi-ega.hex.)


15. The kit & theme packs

cargo run -- --kit generates the fantasy starter kit and installs a playable 4-room world (forest → cave → dungeon → inn, with a key/spellbook/altar quest).

The reusable library lives in kit/:

  • kit/objects.json — 13 fantasy object archetypes.
  • kit/locations/ — prefab rooms (forest, cave, dungeon, inn).
  • kit/ART_MANIFESTO.md — exact sprite specs to replace the placeholders.
  • kit/themes/{scifi,monsters,saucy,horror}/ — each with objects.json (12 archetypes), a sample locations/*.json, and gemini_sprites.md.

Use an object: the kit browser (object tool, [ ]) stamps any of these by clicking. Or copy a { … } block from any objects.json into a room's objects array. Use a location: cp kit/themes/horror/locations/crypt.json rooms/room5.json, then wire its exits in the editor.


16. Games as folders & the file formats

A game is a folder. Zip it, share it, generate it with an LLM — the engine loads it with --game DIR (both binaries):

games/mygame/
  game.json          the manifest (below) — optional, every field defaults
  rooms/room0.json   one RoomDoc per room; start room comes from the manifest
  sprites/*.png      auto-quantized to EGA; filename = sprite name
  sfx/  music/       optional audio-file overrides (§13)

A bare directory with just rooms/ is already a valid game — that's how legacy projects keep loading.

game.json (the manifest):

{
  "name": "The DJ's Lost Fuse",
  "start_room": 0,
  "intro_text": "The party upstairs went quiet an hour ago. Type 'help'.",
  "verbs": [ { "name": "use", "words": ["plug", "spin"] } ],
  "flags": { "met_bouncer": false }
}

verbs merges extra synonyms into the built-in verb table (the AI lane's whitelist is generated from the same table, so they can't drift). flags are the starting flag values for each new game.

A complete worked example ships in games/lost-fuse/ — three rooms demonstrating every mechanic (items, locks, flags, gated dialogue, win), with a guided tour in games/README.md.

Room file format (full schema)

A room is a RoomDoc serialized as JSON:

{
  "strokes": [ <Stroke>, ... ],
  "spawn": [x, y],
  "exits": [N, E, S, W],          // each: a room number or null
  "objects": [ <ObjDef>, ... ],
  "music": 0                       // 0=silence, 1..5 = mood
}

Stroke is an externally-tagged enum — exactly one key:

{ "Rect":    { "x":0,"y":0,"w":160,"h":168,"color":2,"meaning":"Floor" } }
{ "Line":    { "pts":[[x,y],...], "color":15 } }
{ "Brush":   { "pts":[[x,y],...], "color":6,"meaning":"Wall","size":2 } }
{ "Ellipse": { "x":..,"y":..,"w":..,"h":..,"color":..,"meaning":"None" } }
{ "Fill":    { "x":..,"y":..,"color":..,"meaning":"Floor" } }
{ "Image":   { "name":"crate","x":..,"y":..,"meaning":"Wall" } }

meaning is one of "None", "Floor", "Wall", "Water", "Trigger". color is an EGA index 015.

ObjDef:

{
  "name": "gate", "sprite": "door", "x": 80, "y": 120,
  "look": "A heavy gate.", "takeable": false,
  "synonyms": "door portcullis", "use_text": "It grinds open!",
  "needs": "key", "wins": true,
  "requires_flag": "power_on", "sets_flag": "gate_open",
  "dialogue": [ <DlgNode>, ... ]
}

DlgNode: { "says": "...", "choices": [ { "text": "...", "goto": 1, "requires_flag": "", "sets_flag": "" } ] }goto is a node index or -1 to end; the flag fields are optional (§12).

All fields except name/sprite/x/y default if omitted, so hand-written JSON can be minimal. Strokes are replayed into the buffers on load, so rooms stay tiny and re-editable.


17. Programmatic control (CLI · HTTP · MCP · Python)

The engine core is fully headless: a GameState driven by JSON Commands in and Events out. The GUI is just one consumer of that bus — the same bus is exposed as:

  • JSONL stdiomrpgi-headless --game DIR; pipe {"cmd":"parse","text":"take key"} lines in, events stream out.
  • Script replay--script play.jsonl replays a command log deterministically (byte-identical transcripts; the CI golden-test workflow).
  • Headless render--render-room rooms/room0.json out.png bakes any room to a PNG with no window.
  • HTTP--serve 127.0.0.1:7777: POST /command, GET /state, GET /frame.png, GET /events?since=N, POST /rooms/{n}. Python drives it with plain requests.
  • MCP--mcp: a Model Context Protocol server, so Claude (or any MCP client) can both play the game and author it — including mrpgi_render_frame, which returns a real PNG so the model sees its work: claude mcp add mrpgi -- /path/to/mrpgi-headless --mcp --game games/mygame

Full command/event reference and authoring contract: docs/CONTROL.md.


18. Project layout & architecture

Two crates in one workspace:

mrpgi-core/            the headless engine (ZERO window/audio deps — enforced)
  src/state.rs         GameState + the Command/Event bus + fixed-step tick
  src/world.rs         RoomDoc/ObjDef/dialogue data model, World, game folders
  src/parser.rs        data-driven verb table, verb-noun parser, dialogue state
  src/render.rs        headless compositing → RGBA / PNG
  src/framebuffer.rs   visual + priority buffers, the band(y) depth table
  src/picture.rs       drawing primitives (lines, rects, flood-fill, stamps)
  src/view.rs          sprites as cels; ASCII-grid cel builder
  src/sprite.rs        the ego + props: movement, collision, walk-cycle
  src/assets.rs        PNG load + EGA quantize/dither; placeholder sprites
  src/audio.rs         chiptune synthesis + audio cues (content, not output)
  src/ai.rs            the AI parser lane (Ollama / OpenRouter, worker thread)
  src/kit.rs           sample game + starter kit writers
  src/bin/mrpgi-headless/   the CLI/HTTP/MCP surfaces
  tests/engine.rs      parser goldens + a full win-path replay test
mrpgi/                 the macroquad GUI (one consumer of the bus)
  src/main.rs          window, play loop over Commands/Events, HUD
  src/editor.rs        the paint tool (commits edits through the same bus)
  src/sound.rs         audio out: game-folder files override the synth
kit/                   the archetype/theme library + art manifesto
games/                 game folders (lost-fuse example lives here)
sprites/ rooms/        the legacy in-place game (still loads fine)
palettes/              the EGA palette for Aseprite/Inkscape (.gpl, .hex)

Rendering: rooms rasterize into a 160×168 visual buffer + a priority buffer. Each frame, the ego and props are drawn back-to-front by depth; a sprite pixel is only drawn where sprite_priority ≥ scenery_priority (the walk-behind trick). The result is composited headlessly in the core; the GUI just uploads it to a GPU texture. A fixed-step "cycle" (20/s) drives movement, decoupled from frame rate — which is why scripted replays are bit-identical.


19. Troubleshooting

  • Objects are little magenta squares → that sprite PNG doesn't exist yet in sprites/. Make it (see §14) or it's just a placeholder; the object still works.
  • A fill flooded the whole screen → your outline has a gap; the region wasn't sealed. Z to undo and close the gap.
  • Robot stuck after a room transition → the edge you arrived at is walled; leave a walkable gap there (it otherwise falls back to the room's spawn).
  • AI does nothing → check the bottom bar ai: readout; ensure Ollama is running and MRPGI_AI_MODEL matches a pulled model (ollama list). It only fires on unknown verbs.
  • No sound → some machines lack an audio backend; MRPGI stays silent rather than crashing. Check F2 isn't muted.
  • Typing a letter flipped a mode → in play, letters go to the command line; use Tab/F1/F2/Esc (non-letters) for controls.

20. Roadmap & known gaps

  • In-editor dialogue-tree builder and flag-field editing (both are JSON-authored for now; the dialogue/requires_flag/sets_flag fields work — the inspector just doesn't show them yet).
  • The kit-browser villager has no built-in dialogue yet (the live inn one does).
  • More theme packs; title screen / world picker; save/load a playthrough.
  • Water/trigger control lines are reserved but not yet wired to behaviour.
  • True-colour ("HD") background layer and polygon fill regions.
  • Strudel live-coded music as a browser sidecar over the HTTP surface.
  • Pathfinding for click-to-walk (today: greedy steering); cross-room NPC state.

MRPGI — built from "let's reimagine AGI" into a complete, AI-assisted, audible adventure-game maker. Have fun making weird little worlds. 🤖🎸