Captures the 2026-07-05 design session: making MRPGI fully programmatically controllable (MCP + CLI/stdio + HTTP/WebSocket) via a headless mrpgi-core engine behind a typed command/event bus, with the macroquad GUI as one optional front-end. Includes: current-state analysis, the core refactor (GameState with apply/tick), games-as-folders + JSON lore ingestion, an "always want options" audio design (SynthSink / FileSink mp3-ogg-wav / StrudelSink, all toggleable), a P0-P6 roadmap, quick wins, risks, and a source map. Adds docs/architecture.svg (self-contained) plus an inline Mermaid diagram in the handover. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
92 lines
6.0 KiB
XML
92 lines
6.0 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="560" viewBox="0 0 680 560" font-family="-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif">
|
|
<defs>
|
|
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
|
<path d="M2 1L8 5L2 9" fill="none" stroke="#888780" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
</marker>
|
|
</defs>
|
|
<rect x="0" y="0" width="680" height="560" fill="#ffffff"/>
|
|
|
|
<text x="20" y="22" font-size="15" font-weight="500" fill="#2c2c2a">One engine, many front-ends</text>
|
|
<text x="20" y="41" font-size="12" fill="#5f5e5a">Blue = how you drive it · teal = the headless engine core</text>
|
|
|
|
<!-- front-ends -->
|
|
<g>
|
|
<rect x="20" y="56" width="148" height="70" rx="8" fill="#e6f1fb" stroke="#4a90d9"/>
|
|
<text x="94" y="88" font-size="14" font-weight="500" fill="#1b4a7a" text-anchor="middle">macroquad GUI</text>
|
|
<text x="94" y="107" font-size="12" fill="#3a6ea5" text-anchor="middle">play + paint, optional</text>
|
|
</g>
|
|
<g>
|
|
<rect x="184" y="56" width="148" height="70" rx="8" fill="#e6f1fb" stroke="#4a90d9"/>
|
|
<text x="258" y="88" font-size="14" font-weight="500" fill="#1b4a7a" text-anchor="middle">CLI · stdio</text>
|
|
<text x="258" y="107" font-size="12" fill="#3a6ea5" text-anchor="middle">JSONL in, events out</text>
|
|
</g>
|
|
<g>
|
|
<rect x="348" y="56" width="148" height="70" rx="8" fill="#e6f1fb" stroke="#4a90d9"/>
|
|
<text x="422" y="88" font-size="14" font-weight="500" fill="#1b4a7a" text-anchor="middle">HTTP + WebSocket</text>
|
|
<text x="422" y="107" font-size="12" fill="#3a6ea5" text-anchor="middle">REST · SSE · Python</text>
|
|
</g>
|
|
<g>
|
|
<rect x="512" y="56" width="148" height="70" rx="8" fill="#e6f1fb" stroke="#4a90d9"/>
|
|
<text x="586" y="88" font-size="14" font-weight="500" fill="#1b4a7a" text-anchor="middle">MCP server</text>
|
|
<text x="586" y="107" font-size="12" fill="#3a6ea5" text-anchor="middle">Claude authors + plays</text>
|
|
</g>
|
|
|
|
<line x1="94" y1="126" x2="94" y2="149" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
<line x1="258" y1="126" x2="258" y2="149" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
<line x1="422" y1="126" x2="422" y2="149" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
<line x1="586" y1="126" x2="586" y2="149" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
|
|
<!-- bus -->
|
|
<rect x="20" y="150" width="640" height="44" rx="8" fill="#f1efe8" stroke="#b4b2a9"/>
|
|
<text x="340" y="169" font-size="14" font-weight="500" fill="#2c2c2a" text-anchor="middle">Command / event bus</text>
|
|
<text x="340" y="185" font-size="12" fill="#5f5e5a" text-anchor="middle">commands down · events up</text>
|
|
|
|
<line x1="340" y1="194" x2="340" y2="213" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
|
|
<!-- core -->
|
|
<rect x="20" y="214" width="640" height="176" rx="10" fill="#f7f7f5" stroke="#c9c7be"/>
|
|
<rect x="32" y="224" width="266" height="26" rx="13" fill="#e1f5ee" stroke="#1d9e75"/>
|
|
<text x="165" y="242" font-size="14" font-weight="500" fill="#0f6e56" text-anchor="middle">mrpgi-core · headless (no macroquad)</text>
|
|
|
|
<rect x="32" y="262" width="292" height="46" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="44" y="282" font-size="14" font-weight="500" fill="#2c2c2a">GameState</text>
|
|
<text x="44" y="299" font-size="12" fill="#5f5e5a">apply(cmd) → events · tick(dt) → events</text>
|
|
|
|
<rect x="340" y="262" width="308" height="46" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="352" y="282" font-size="14" font-weight="500" fill="#2c2c2a">Parser + AI lane</text>
|
|
<text x="352" y="299" font-size="12" fill="#5f5e5a">verb·noun → authoritative logic</text>
|
|
|
|
<rect x="32" y="320" width="196" height="46" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="42" y="340" font-size="14" font-weight="500" fill="#2c2c2a">FrameBuffer</text>
|
|
<text x="42" y="357" font-size="12" fill="#5f5e5a">visual + priority buffers</text>
|
|
|
|
<rect x="240" y="320" width="196" height="46" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="250" y="340" font-size="14" font-weight="500" fill="#2c2c2a">World</text>
|
|
<text x="250" y="357" font-size="12" fill="#5f5e5a">rooms · exits · flags/vars</text>
|
|
|
|
<rect x="448" y="320" width="200" height="46" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="458" y="340" font-size="14" font-weight="500" fill="#2c2c2a">render_visual()</text>
|
|
<text x="458" y="357" font-size="12" fill="#5f5e5a">→ PNG, no window</text>
|
|
|
|
<line x1="170" y1="416" x2="170" y2="392" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
<text x="182" y="409" font-size="12" fill="#5f5e5a">load_game · lore upsert</text>
|
|
<line x1="510" y1="392" x2="510" y2="416" stroke="#888780" stroke-width="1.5" marker-end="url(#arrow)"/>
|
|
<text x="522" y="409" font-size="12" fill="#5f5e5a">AudioSink events</text>
|
|
|
|
<!-- data folder -->
|
|
<rect x="20" y="418" width="300" height="122" rx="10" fill="#f7f7f5" stroke="#c9c7be"/>
|
|
<text x="34" y="442" font-size="14" font-weight="500" fill="#2c2c2a">A game = a folder</text>
|
|
<text x="34" y="464" font-size="12" fill="#5f5e5a">games/<name>/</text>
|
|
<text x="34" y="483" font-size="12" fill="#5f5e5a">game.json — manifest, verbs</text>
|
|
<text x="34" y="501" font-size="12" fill="#5f5e5a">rooms/*.json — art, objects, dialogue</text>
|
|
<text x="34" y="519" font-size="12" fill="#5f5e5a">sprites/*.png — cels</text>
|
|
|
|
<!-- audio -->
|
|
<rect x="360" y="418" width="300" height="122" rx="10" fill="#f7f7f5" stroke="#c9c7be"/>
|
|
<text x="374" y="442" font-size="14" font-weight="500" fill="#2c2c2a">Audio out — toggle both / either / off</text>
|
|
<rect x="374" y="456" width="272" height="32" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="386" y="476" font-size="12" fill="#5f5e5a">Native chiptune · SynthSink (offline)</text>
|
|
<rect x="374" y="496" width="272" height="32" rx="6" fill="#ffffff" stroke="#d3d1c7"/>
|
|
<text x="386" y="516" font-size="12" fill="#5f5e5a">FileSink (mp3/ogg/wav) · StrudelSink (browser)</text>
|
|
</svg>
|