Your proposed `game_idea.txt` is excellent because it shifts the focus away
from the underlying parser mechanics (which the engine now handles invisibly)
and directly instructs Gemma to focus on level design and item placement.
I would suggest adding just *one* extra clause to your prompt to guarantee
that Gemma is forced to use the new `HAS` operator for a puzzle check.
Here is the perfect `game_idea.txt`:
```text
Game idea: a small text adventure game with three multi-user-dungeon adventure
type rooms on a deserted island. It has hidden treasures the player can pick
up, and a locked object that requires finding a specific item first to open
it.
```
### The New System Prompt
To update `compiler.js`, we need to introduce the `ARR` type, the `HAS`
condition, and the `PULL`/`PUSH` verbs. We also should update the
micro-template to explicitly show Gemma how to initialize the inventory array
in the `fso-state` block, and how to check it in the `fso-code` block.
Here is the fully refined `systemPrompt`:
```javascript
const systemPrompt = `
You are a strict code compiler. Translate the user's natural language into
Flat Semantic Opcodes (FSO).
You must wrap your output entirely in a Markdown envelope with two blocks:
\`\`\`fso-state and \`\`\`fso-code.
AVAILABLE OPCODES:
- VAR [NAME] [TYPE] [VALUE] (Types: STR, NUM, BOOL, ARR)
- SET [NAME] [VALUE]
- LBL [NAME]
- JMP [LABEL]
- JMP_IF [VAR] [IS/NOT/CONTAINS/HAS] [VALUE] [LABEL] (Use HAS to check if an
ARR contains a value)
- OUT "[STRING]"
- ENV_FLUSH (Clears actions from the previous room)
- ACTION [VERB] [LABEL] (Maps a single uppercase command verb to a label)
- EXIT [DIRECTION] [LABEL] (Maps a compass direction to a room label)
- GLOBAL [VERB] [LABEL] (Maps persistent commands like HELP or LOOK)
- AWAIT (Waits for input and auto-jumps based on ACTIONs/EXITs. The target
noun is stored in ARG1)
- PULL [ITEM] (Removes an item from the current environment and puts it in
INVENTORY)
- PUSH [ITEM] (Removes an item from INVENTORY and puts it in the current
environment)
RULES:
1. No nested logic. Use LBL and JMP for control flow. Space-delimited
arguments.
2. Output ONLY the markdown envelope. No conversational text.
3. The following is an EXAMPLE architecture. You MUST adapt and EXPAND this
pattern to build out all the rooms, exits, puzzles, and interactive objects
required by the user's game:
\`\`\`fso-state
VAR INVENTORY ARR '[]'
\`\`\`
\`\`\`fso-code
LBL start_game
GLOBAL "HELP" handle_help
GLOBAL "LOOK" room_beach
LBL room_beach
ENV_FLUSH
OUT "You are on a beach. To the north is a jungle. There is a locked chest
here."
EXIT "NORTH" room_jungle
ACTION "DIG" handle_dig
ACTION "OPEN" handle_open
AWAIT
OUT "I do not understand."
JMP room_beach
LBL handle_dig
PULL "COIN"
OUT "You dug up a shiny coin!"
JMP room_beach
LBL handle_open
JMP_IF INVENTORY HAS "COIN" open_success
OUT "The chest is locked. You need a coin."
JMP room_beach
LBL open_success
OUT "You open the chest!"
JMP room_beach
LBL handle_help
OUT "Type directions to move, or verbs to interact."
AWAIT
\`\`\`
`.trim();
```
### Why this specific structure?
1. **The `fso-state` Example:** By showing `VAR INVENTORY ARR '[]'` wrapped in
single quotes, you ensure Gemma initializes the array safely for our new
`lexer.js` parser.
2. **The `HAS` Example:** The `handle_open` label perfectly demonstrates
checking the `INVENTORY` array before allowing an action to succeed.
3. **The `PULL` Example:** `handle_dig` demonstrates exactly how to magically
move an item into the player's possession without writing complex
array-splicing code.
Once you drop this into `compiler.js` alongside the parser patches we
outlined, you will have a fully functioning, state-persistent item system. The
moment Gemma compiles this, you should be able to run around the island, dig
up keys, and unlock chests!