@motioneffector/parser
A natural language command parser for text adventures and interactive fiction. You give it player input like "get the red ball from the chest" and it gives you a structured command object: verb GET, subject {id: "ball-red"}, object {id: "chest-1"}, preposition from. Your job is to provide a resolver function that connects noun phrases to your game's entities—the parser handles everything else.
I want to...
| Goal | Where to go |
|---|---|
| Get up and running quickly | Your First Parse |
| Understand how vocabulary works | Vocabulary |
| Parse commands in my game | Parsing Commands |
| Handle ambiguous entities | Handling Disambiguation |
| Add custom verbs | Custom Vocabulary |
| Handle parse errors gracefully | Error Handling |
| Look up a specific method | API Reference |
Key Concepts
Vocabulary
The vocabulary defines what words the parser recognizes: verbs with their synonyms and argument patterns, directions with shortcuts, prepositions that connect objects, and articles to strip. Ships with 27 verbs and 12 directions out of the box.
Verb Patterns
Every verb has a pattern that tells the parser what arguments to expect. look expects nothing, get expects one thing, put expects a thing and a destination, go expects a direction, and say captures everything as text.
Entity Resolution
You provide a resolver function that the parser calls to look up entities. Given a noun and adjectives, you return matching entities from your game state. Return one for success, multiple for disambiguation, or empty for "I don't see that here."
Parse Results
The parser returns a discriminated union—check the type field to know what happened. You'll get command for success, ambiguous when multiple entities match, unknown_verb or unknown_noun for unrecognized words, or parse_error for structural problems.
Quick Example
import { createParser } from '@motioneffector/parser'
// Your resolver connects the parser to your game state
const parser = createParser({
resolver: (noun, adjectives, scope) => {
// Look up entities by name in current room
const room = scope.room as { items: Array<{ id: string; name: string }> }
return room.items.filter(item => item.name === noun)
}
})
// Parse player input
const result = parser.parse('get lamp', {
scope: { room: { items: [{ id: 'lamp-1', name: 'lamp' }] } }
})
if (result.type === 'command') {
console.log(result.command.verb) // "GET"
console.log(result.command.subject?.id) // "lamp-1"
}