Skip to content

Latest commit

 

History

History
247 lines (182 loc) · 9.07 KB

README.md

File metadata and controls

247 lines (182 loc) · 9.07 KB

AIGE: The AI Game Engine

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.


View Docs Made with TypeScript

NPM Version CircleCI Last Commit Open issues Closed issues

Sponsors Contributors GitHub license PRs Welcome

Followers Watchers Stars


Features

  • 🎮 Create games in any universe
  • 🗨️ Chat with any character
  • 🎨 Generate images for various game elements using DALL-E
  • 👨‍💻 An "action" in the game can be any prompt, allowing virtually infinite possibilities
  • 📝 The game will suggest actions for the player to choose from
  • 🧠 Manage game state with a simple API
  • 📦 Export and import games as JSON
  • 🚨 Track game events with event listeners
  • 🧰 Track stats, scene, inventory, characters, abilities, quests, and more
  • 🤖 Powered by OpenAI API (planned support for additional LLMs)

asciicast


Table of Contents


CLI

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

Installation

npm install @aige/core # or your package manager's equivalent (pnpm recommended)

Documentation

View the docs on aige.games

Simple Example

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()))

Full Example

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.

Development

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.

Notes

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:

  • Allow custom schemas to reduce token usage by pruning unused data, and allowing flexibility in game structure
  • Chunk the creation and action calls into smaller pieces to reduce token usage per call, giving faster responses

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.