AIGE is a Node.js library that utilizes the OpenAI API to generate text-based games in any universe.
Developers can integrate AIGE into their own projects to create games that are unique every time.
AI-based games can go off the rails and not make sense sometimes, but that's part of the fun!
Made with ❤️ by Jay Mathis
Please consider becoming a sponsor or buying tokens on Imagined.Quest if you appreciate my work.
Just want to play some games? Try the CLI!
OPENAI_API_KEY=sk-youropenaikey npx @aige/core@latest
AIGE vX.Y.Z
https://aige.games
Type "help" for a list of commands
? 🎮 create
npm install @aige/core # or your package manager's equivalent (pnpm recommended)
import fs from 'node:fs'
import { Game, GameEvent } from '@aige/core'
const game = new Game({ clientOptions: { apiKey: 'sk-openaikey' } })
await game.init()
console.log(`${game.data.scene_emoji} ${game.scene}`)
const action = game.data.actions[0]
console.log(`Performing action: ${action}`)
await game.action(action)
console.log(`${game.data.scene_emoji} ${game.scene}`)
await game.action('Attack the nearest enemy')
console.log(game.inspect())
game.on(GameEvent.chat, ({ character, dialog }) => console.log(`${character.name}: ${dialog}`))
await game.chat(game.data.characters[0], 'Hello!')
const images = await game.images({ player: true, scene: true })
console.dir(images)
fs.writeFileSync('./game.json', JSON.stringify(game.export()))
import fs from 'node:fs'
import { Game, GameEvent } from '@aige/core'
// If using the environment variable, you can omit the apiKey option entirely
const OPENAI_API_KEY = process.env.OPENAI_API_KEY || 'your-openai-api-key'
// completely random game
const game1 = new Game({ clientOptions: { apiKey: OPENAI_API_KEY } })
// import a game from a JSON export
const game2 = new Game({ clientOptions: { apiKey: OPENAI_API_KEY } })
game2.import(JSON.parse(fs.readFileSync('./game.json', 'utf8')))
// specify game options
const game3 = new Game({
clientOptions: { apiKey: OPENAI_API_KEY },
universe: 'Warhammer 40K',
playerName: 'Konrad Curze',
playerClass: 'Primarch'
})
// change the way the game is created (can also be specified in Game constructor)
game1.options.prompts.create = 'Create game but all text in every argument should be uppercase'
game1.options.prompts.name = 'Get the player name but make it hard to pronounce'
game1.options.prompts.class = 'Get the player class but make it all numbers'
// Initializing is only necessary for new games, not imported games
await game1.init()
await game3.init()
// Game states:
console.log(game1.inspect())
console.log(game2.inspect())
console.log(game3.inspect())
// Perform actions:
const action = game1.data.actions[Math.floor(Math.random() * game1.data.actions.length)]
await game1.action(action) // Use a suggested action
await game2.action('Explore the area')
await game3.action('Do Night Haunter things')
// Manually set a game value:
game1.set('health', 10000)
game2.set('abilities[0].name', 'Renamed Ability')
game3.set('characters[0].hostile', true)
// Add event listeners:
game1.on(GameEvent.gain, ({ attribute, amount }) => console.log(`Gained ${amount} ${attribute}`))
game2.on(GameEvent.loss, ({ attribute, amount }) => console.log(`Lost ${amount} ${attribute}`))
game3.on(GameEvent.chat, ({ character, dialog }) => console.log(`${character.name}: ${dialog}`))
// Chat with a character:
await game3.chat(game3.data.characters[0], 'Stop doing crime!')
// Generate images:
const item = game3.data.inventory[0]
const ability = game3.data.abilities[0]
// You can provide any combination of the following options to the images method:
const images = await game3.images({
player: true,
scene: true,
character,
ability,
item
}, {
user: 'user-id', // optional
size: '512x512' // 256x256 | 512x512 (default) | 1024x1024 | 1792x1024 | 1024x1792
style: 'vivid' // vivid (default) | natural
quality: 'hd' // hd (default) | standard
model: 'dall-e-2' // dall-e-2 (default) | dall-e-3
response_format: 'url' // url (default) | b64_json
})
console.log(images)
// { player?: 'https://...', scene?: 'https://...',
// character?: 'https://...', ability?: 'https://...', item?: 'https://...' }
// Save the game state to a JSON file
fs.writeFileSync('./game1.json', JSON.stringify(game1.export(), null, 2))
fs.writeFileSync('./game2.json', JSON.stringify(game2.export(), null, 2))
fs.writeFileSync('./game3.json', JSON.stringify(game3.export(), null, 2))
See tests and cli.ts for more examples on how to use the library.
Run the following commands:
git clone https://github.com/mathiscode/aige.git
cd aige
echo "OPENAI_API_KEY=sk-youropenaikey" > .env
pnpm install
pnpm test
All scripts:
pnpm test # run tests one time
pnpm test:watch # run tests and watch for changes
pnpm test:coverage # run tests and generate a coverage report
pnpm build # build the library and docs
pnpm build:library # build the library
pnpm build:docs # build the docs
pnpm build:docs:watch # build the docs and watch for changes
pnpm dev:cli # run the CLI with the Node.js debugger attached
There is a launch.json
file included for debugging in VSCode.
OpenAI's API can sometimes be slow to respond with larger schemas, and the create
and update
tools have fairly heavy schemas. As time goes on, both OpenAI and AIGE will improve and become faster.
Optimizations Coming:
The default models are gpt-3.5-turbo-1106
and dall-e-2
. You can set the models in the GameClientOptions to use others. Creating a game and performing an action uses ~2000-3000 tokens.