A powerful, reactive text-based game engine for React applications. Build interactive narrative experiences with TypeScript, featuring state management, multiple passage types, and a comprehensive save system.
Building interactive narrative experiences shouldn't require reinventing the wheel. React Text Game provides a production-ready game engine that handles the complexity of state management, save systems, and UI components—so you can focus on crafting your story.
- Zero boilerplate - Start building immediately with factory functions and pre-built components
- Production-ready - Built-in save system with IndexedDB persistence and encrypted exports
- Author-friendly - Write passages in Markdown (MDX) or programmatically with TypeScript
- Fully customizable - Use our UI components or build your own with the core engine
- Type-safe - Catch errors at compile time with comprehensive TypeScript support
- Modern React - Built for React 18+ with hooks and reactive state management
Whether you're building a visual novel, interactive fiction, or educational narrative experience, React Text Game provides the foundation to ship faster.
- Reactive State Management - Built on Valtio for automatic UI updates
- Multiple Passage Types - Story passages, Interactive Maps, and custom Widget passages
- Comprehensive Save System - IndexedDB persistence with encrypted export/import
- Audio System - Full-featured audio management with reactive state, persistence, and global controls
- Themeable UI Components - Tailwind CSS v4 with semantic color tokens
- Internationalization - i18next-powered translations with persistent language switching
- Type-Safe - Full TypeScript support with detailed JSDoc documentation
- Factory-Based Entities - Plain-object factories with optional class-based escape hatches
- React Integration - Built-in hooks and React 19 support
- Modular Architecture - Use core engine independently or with UI components
This monorepo contains three publishable packages:
The core game engine providing:
- Game orchestration and entity registry
- Reactive state management (Valtio)
- JSONPath-based storage system
- Story and Interactive Map passages
- Audio system with reactive state and persistence
- Save/load system with auto-save
- React hooks for game integration
UI components library featuring:
- Pre-built game components (GameProvider, MainMenu, PassageController)
- Story and Interactive Map renderers
- Save/Load modals with slot management
- Tailwind CSS v4 semantic theming
- Dark mode support
MDX integration package enabling:
- Author-friendly Markdown syntax for game passages
- Seamless React component integration in narratives
- Type-safe custom components with full TypeScript support
- Vite plugin for optimized build pipeline
- Automatic metadata and story structure extraction
- Runtime-evaluated dynamic variables
# Install core and UI packages
bun add @react-text-game/core @react-text-game/ui
# Optional: Add MDX support for Markdown-based passages
bun add @react-text-game/mdx @mdx-js/mdx @mdx-js/react
# Or use npm/yarn/pnpm
npm install @react-text-game/core @react-text-game/ui
npm install @react-text-game/mdx @mdx-js/mdx @mdx-js/reactimport { Game, createEntity, newStory } from '@react-text-game/core';
import { GameProvider, PassageController } from '@react-text-game/ui';
import '@react-text-game/ui/styles';
// Initialize the game
await Game.init({
gameId: 'my-game',
gameName: 'My Adventure',
translations: {
defaultLanguage: 'en',
fallbackLanguage: 'en',
resources: {
en: {
passages: {
intro: 'Welcome to the Game'
}
}
}
}
});
// Create a game entity (factory-first approach)
const player = createEntity('player', {
name: 'Hero',
stats: {
health: 100,
mana: 50,
},
inventory: [] as string[],
});
// Create a story passage
const intro = newStory('intro', () => [
{
type: 'header',
content: 'Welcome to the Game',
props: { level: 1 }
},
{
type: 'text',
content: `Hello, ${player.name}!`
},
{
type: 'actions',
content: [
{
label: 'Start Adventure',
action: () => Game.jumpTo('chapter-1')
}
]
}
]);
// React component
function App() {
return (
<GameProvider game={Game}>
<PassageController />
</GameProvider>
);
}
// Start the game
Game.jumpTo(intro);Prefer class-based entities? Extend
BaseGameObjectdirectly—the factory and class APIs work side by side.
React Text Game ships with i18next baked into the core engine and the UI package. The translations option you pass to Game.init accepts the same structure as i18next resources, and the engine automatically persists the player’s language choice in the save database.
- Core exports
useGameTranslationandgetGameTranslationso you can localize passages, UI, and game logic. - The optional UI package exposes a
LanguageTogglecomponent and contributes default English strings under theuinamespace; your resources override them per language. - Supported language codes are derived from your resources, and missing keys fall back to the language you declare in
fallbackLanguage.
import { useGameTranslation } from '@react-text-game/core/i18n';
import { LanguageToggle } from '@react-text-game/ui';
function StatusBar() {
const { t, currentLanguage } = useGameTranslation('common');
return (
<header className="flex items-center gap-4">
<span>{t('status.currentLanguage', { language: currentLanguage })}</span>
<LanguageToggle />
</header>
);
}- Full Documentation - Comprehensive guides and tutorials (Docusaurus site)
- API Reference - Auto-generated TypeDoc API documentation
- Example Game - Complete game implementation example
This is a Turborepo monorepo using Bun as the package manager.
- Bun 1.2.23 or later
- Node.js 18 or later
# Install dependencies
bun install
# Run all packages in watch mode
bun run dev
# Build all packages
bun run build
# Type checking
bun run check-types
# Linting
bun run lint
# Code formatting
bun run formatTarget specific packages or apps:
# Run dev for specific app
bun run dev --filter=example-game
# Build only the core package
bun run build --filter=@react-text-game/core
# Build both packages
bun run build --filter='@react-text-game/*'react-text-game/
├── packages/
│ ├── core/ # @react-text-game/core - Game engine
│ ├── ui/ # @react-text-game/ui - UI components
│ └── mdx/ # @react-text-game/mdx - MDX integration
├── apps/
│ ├── docs/ # Docusaurus documentation site
│ ├── example-game/ # Example game implementation
│ ├── core-test-app/ # Core package testing
│ └── ui-test-app/ # UI components testing
└── turbo.json # Turborepo configuration
Note: The apps/ directory contains examples, tests, and documentation. The main deliverables are the packages in packages/.
Contributions are welcome! To contribute:
- Fork the repository and create a new branch for your feature or bugfix
- Install dependencies with
bun install - Follow existing patterns - Use factory functions, semantic colors in UI, and TypeScript types
- Test your changes in the test apps (
apps/core-test-apporapps/ui-test-app) - Ensure code quality:
- Run
bun run lintto check for linting issues - Run
bun run check-typesto verify TypeScript types - Run
bun run formatto format code with Prettier
- Run
- Create a changeset if you're modifying a package:
- Run
bun run changesetand follow the prompts - This helps with version management and changelog generation
- Run
- Submit a pull request with a clear description of your changes
Please ensure all checks pass before submitting your PR. If you're adding new features, consider updating the documentation in apps/docs.
MIT (c) laruss
- NPM Packages:
- Repository: GitHub
- Issues: Report bugs and request features on GitHub Issues
