A modern, TypeScript-based platform for creating parser-based interactive fiction.
npm install @sharpee/sharpee@betaBeta Release: The platform is feature-complete for story development. Documentation is being expanded.
The @sharpee/sharpee meta-package installs all core packages:
| Package | Description |
|---|---|
@sharpee/core |
Event system, types, utilities |
@sharpee/world-model |
Entity system with traits and behaviors |
@sharpee/stdlib |
43 standard IF actions |
@sharpee/engine |
Game runtime and command processor |
@sharpee/parser-en-us |
English natural language parser |
@sharpee/lang-en-us |
English language messages |
@sharpee/if-domain |
Grammar builder interfaces |
@sharpee/if-services |
Service interfaces |
@sharpee/event-processor |
Event processing |
@sharpee/text-services |
Text formatting |
| Package | Description |
|---|---|
@sharpee/transcript-tester |
Test stories via transcript files |
@sharpee/client-core |
Shared client infrastructure |
@sharpee/forge |
Story scaffolding and build tools |
- Event-Driven Architecture - Immutable semantic events for all state changes
- Natural Language Parser - Understands complex player commands with slot constraints
- Rich World Model - Entities with traits, behaviors, and relationships
- 43 Standard Actions - take, drop, open, close, lock, unlock, wear, eat, drink, attack, and more
- Four-Phase Action Pattern - Consistent validate/execute/report/blocked flow
- Capability Dispatch - Entity-specific handling for generic verbs
- NPC System - Autonomous characters with behaviors and schedules
- Daemons & Fuses - Timed events and background processes
- Perception System - Handles darkness, blindness, and sensory restrictions
- Type-Safe - Full TypeScript with strict typing
- Language Layer Separation - All text output goes through localizable message IDs
The repository includes several example stories:
| Story | Description |
|---|---|
cloak-of-darkness |
Classic IF demo game - simple introduction |
secretletter2025 |
Mystery adventure with NPCs |
reflections |
Atmospheric puzzle game |
dungeo |
Mainframe Zork implementation (~191 rooms, in progress) |
+-----------------------------------------------+
| Your Story |
+-----------------------------------------------+
| stdlib (actions) | lang-en-us (messages) |
+-----------------------------------------------+
| world-model | parser-en-us | engine |
+-----------------------------------------------+
| core (events) |
+-----------------------------------------------+
- Actions emit semantic events, not text - The language layer converts message IDs to prose
- Behaviors own mutations - Actions coordinate, behaviors perform state changes
- Traits compose entity capabilities - Add container, lockable, wearable, etc.
- Parser scope is permissive - Actions decide if visibility is truly required
# Clone and setup
git clone https://github.com/ChicagoDave/sharpee.git
cd sharpee
pnpm install
pnpm build
# Run all tests
pnpm test
# Run specific package tests
pnpm --filter '@sharpee/stdlib' test
# Run story transcripts
node packages/transcript-tester/dist/cli.js stories/dungeo --allThe stdlib includes 43 actions across these categories:
Movement: going, entering, exiting Manipulation: taking, dropping, putting, inserting, removing, giving, throwing Containers/Doors: opening, closing, locking, unlocking Examination: looking, examining, searching, reading Interaction: talking, showing, attacking Devices: switching on/off, pushing, pulling, raising, lowering Wearables: wearing, taking off Consumables: eating, drinking Senses: touching, smelling, listening Meta: inventory, score, help, save, restore, restart, quit, undo, wait, about, sleep
- Core Concepts - Entity system, traits, actions, events
- Creating Stories - Developer guide for new stories
- Architecture Decisions - Design rationale (ADRs)
See Creating Stories for a complete guide. Quick overview:
import { Story, StoryConfig } from '@sharpee/engine';
import { WorldModel, EntityType, TraitType } from '@sharpee/world-model';
export const config: StoryConfig = {
id: "my-story",
title: "My Story",
author: "Your Name",
version: "1.0.0"
};
export class MyStory implements Story {
config = config;
initializeWorld(world: WorldModel): void {
// Create rooms
const room = world.createEntity('Starting Room', EntityType.ROOM);
room.add({ type: TraitType.ROOM, isDark: false });
// Create objects
const lamp = world.createEntity('brass lamp', EntityType.OBJECT);
lamp.add({ type: TraitType.PORTABLE });
world.moveEntity(lamp.id, room.id);
// Set player location
const player = world.getPlayer();
world.moveEntity(player.id, room.id);
}
}MIT License - see LICENSE
Built for the interactive fiction community.