Spaces:
Sleeping
Sleeping
bulk
Browse filesThis view is limited to 50 files because it contains too many changes. Β
See raw diff
- .DS_Store +0 -0
- .dockerignore +39 -0
- .eslintignore +7 -0
- .eslintrc.js +22 -0
- .gitattributes +0 -35
- .github/workflows/hf-sync.yml +0 -22
- .gitignore +45 -0
- .prettierrc +7 -0
- .vscode/convex.code-snippets +102 -0
- .vscode/settings.json +21 -0
- ARCHITECTURE.md +301 -0
- Dockerfile +0 -17
- Justfile +30 -0
- LICENSE +21 -0
- README.md +434 -25
- README.md.yml +0 -18
- {patches/assets β assets}/32x32folk.png +0 -0
- {patches/assets β assets}/GrayCat.png +0 -0
- {patches/assets β assets}/OrangeCat.png +0 -0
- {patches/assets β assets}/a16z.png +0 -0
- {patches/assets β assets}/background.webp +0 -0
- {patches/assets β assets}/close.svg +0 -0
- {patches/assets β assets}/cloud.jpg +0 -0
- {patches/assets β assets}/convex-bg.webp +0 -0
- {patches/assets β assets}/convex.svg +0 -0
- {patches/assets β assets}/favicon.ico +0 -0
- {patches/assets β assets}/fonts/upheaval_pro.ttf +0 -0
- {patches/assets β assets}/fonts/vcr_osd_mono.ttf +0 -0
- {patches/assets β assets}/heart-empty.png +0 -0
- {patches/assets β assets}/help.svg +0 -0
- {patches/assets β assets}/hf.svg +0 -0
- {patches/assets β assets}/interact.svg +0 -0
- {patches/assets β assets}/magecity.png +0 -0
- map.png β assets/map.png +0 -0
- {patches/assets β assets}/map_night.png +0 -0
- {patches/assets β assets}/player.png +0 -0
- {patches/assets β assets}/rpg-tileset.png +0 -0
- {patches/assets β assets}/spritesheets/campfire.png +0 -0
- {patches/assets β assets}/spritesheets/gentlesparkle32.png +0 -0
- {patches/assets β assets}/spritesheets/gentlewaterfall32.png +0 -0
- {patches/assets β assets}/spritesheets/windmill.png +0 -0
- {patches/assets β assets}/star.svg +0 -0
- {patches/assets β assets}/tilemap.json +0 -0
- {patches/assets β assets}/ui/box.svg +0 -0
- {patches/assets β assets}/ui/bubble-left.svg +0 -0
- {patches/assets β assets}/ui/bubble-right.svg +0 -0
- {patches/assets β assets}/ui/button.svg +0 -0
- {patches/assets β assets}/ui/button_pressed.svg +0 -0
- {patches/assets β assets}/ui/chats.svg +0 -0
- {patches/assets β assets}/ui/desc.svg +0 -0
.DS_Store
CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
|
|
.dockerignore
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
2 |
+
|
3 |
+
# dependencies
|
4 |
+
/node_modules
|
5 |
+
game/node_modules/
|
6 |
+
/.pnp
|
7 |
+
.pnp.js
|
8 |
+
|
9 |
+
# testing
|
10 |
+
/coverage
|
11 |
+
|
12 |
+
# next.js
|
13 |
+
/.next/
|
14 |
+
/out/
|
15 |
+
|
16 |
+
# production
|
17 |
+
/build
|
18 |
+
|
19 |
+
# misc
|
20 |
+
.DS_Store
|
21 |
+
*.pem
|
22 |
+
|
23 |
+
# debug
|
24 |
+
npm-debug.log*
|
25 |
+
yarn-debug.log*
|
26 |
+
yarn-error.log*
|
27 |
+
|
28 |
+
# local env files
|
29 |
+
.env*.local
|
30 |
+
|
31 |
+
# vercel
|
32 |
+
.vercel
|
33 |
+
|
34 |
+
# typescript
|
35 |
+
*.tsbuildinfo
|
36 |
+
next-env.d.ts
|
37 |
+
.env
|
38 |
+
/.env.prod
|
39 |
+
/fly.toml
|
.eslintignore
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
webpack*
|
2 |
+
.eslintrc.js
|
3 |
+
next.config.js
|
4 |
+
tailwind.config.js
|
5 |
+
postcss.config.js
|
6 |
+
convex/_generated/*
|
7 |
+
dist/*
|
.eslintrc.js
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export default {
|
2 |
+
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
|
3 |
+
plugins: ['@typescript-eslint'],
|
4 |
+
extends: [
|
5 |
+
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
|
6 |
+
'plugin:@typescript-eslint/recommended-type-checked',
|
7 |
+
],
|
8 |
+
parserOptions: {
|
9 |
+
project: './tsconfig.json',
|
10 |
+
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
|
11 |
+
sourceType: 'module', // Allows for the use of imports
|
12 |
+
},
|
13 |
+
rules: {
|
14 |
+
'@typescript-eslint/no-explicit-any': 'off',
|
15 |
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
16 |
+
'@typescript-eslint/no-unused-vars': [
|
17 |
+
'warn',
|
18 |
+
{ varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
|
19 |
+
],
|
20 |
+
'@typescript-eslint/no-non-null-assertion': 'off',
|
21 |
+
},
|
22 |
+
};
|
.gitattributes
DELETED
@@ -1,35 +0,0 @@
|
|
1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.github/workflows/hf-sync.yml
DELETED
@@ -1,22 +0,0 @@
|
|
1 |
-
name: Sync to Hugging Face Spaces
|
2 |
-
on:
|
3 |
-
push:
|
4 |
-
branches:
|
5 |
-
- main
|
6 |
-
jobs:
|
7 |
-
sync:
|
8 |
-
name: Sync
|
9 |
-
runs-on: ubuntu-latest
|
10 |
-
steps:
|
11 |
-
- name: Checkout Repository
|
12 |
-
uses: actions/checkout@v4
|
13 |
-
with:
|
14 |
-
lfs: true
|
15 |
-
- name: Sync to Hugging Face Spaces
|
16 |
-
uses: JacobLinCool/huggingface-sync@v1
|
17 |
-
with:
|
18 |
-
github: ${{ secrets.GITHUB_TOKEN }}
|
19 |
-
user: ${{ vars.HF_SPACE_OWNER }}
|
20 |
-
space: ${{ vars.HF_SPACE_NAME }}
|
21 |
-
token: ${{ secrets.HF_TOKEN }}
|
22 |
-
configuration: "README.md.yml"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
2 |
+
|
3 |
+
# dependencies
|
4 |
+
/node_modules
|
5 |
+
game/node_modules/
|
6 |
+
/.pnp
|
7 |
+
.pnp.js
|
8 |
+
|
9 |
+
# testing
|
10 |
+
/coverage
|
11 |
+
|
12 |
+
# next.js
|
13 |
+
/.next/
|
14 |
+
/out/
|
15 |
+
|
16 |
+
# production
|
17 |
+
/build
|
18 |
+
|
19 |
+
# misc
|
20 |
+
.DS_Store
|
21 |
+
*.pem
|
22 |
+
|
23 |
+
# debug
|
24 |
+
npm-debug.log*
|
25 |
+
yarn-debug.log*
|
26 |
+
yarn-error.log*
|
27 |
+
|
28 |
+
# local env files
|
29 |
+
.env*.local
|
30 |
+
|
31 |
+
# vercel
|
32 |
+
.vercel
|
33 |
+
|
34 |
+
# typescript
|
35 |
+
*.tsbuildinfo
|
36 |
+
next-env.d.ts
|
37 |
+
.env
|
38 |
+
/.env.prod
|
39 |
+
/fly.toml
|
40 |
+
|
41 |
+
# Vite build
|
42 |
+
dist
|
43 |
+
convex-local-backend*
|
44 |
+
convex_local_storage
|
45 |
+
convex_local_backend.sqlite3
|
.prettierrc
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"trailingComma": "all",
|
3 |
+
"singleQuote": true,
|
4 |
+
"bracketSpacing": true,
|
5 |
+
"tabWidth": 2,
|
6 |
+
"printWidth": 100
|
7 |
+
}
|
.vscode/convex.code-snippets
ADDED
@@ -0,0 +1,102 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"Convex Imports": {
|
3 |
+
"prefix": "convex:imports",
|
4 |
+
"body": [
|
5 |
+
"import { v } from \"convex/values\";",
|
6 |
+
"import { api, internal } from \"./_generated/api\";",
|
7 |
+
"import { Doc, Id } from \"./_generated/dataModel\";",
|
8 |
+
"import {",
|
9 |
+
" action,",
|
10 |
+
" internalAction,",
|
11 |
+
" internalMutation,",
|
12 |
+
" internalQuery,",
|
13 |
+
" mutation,",
|
14 |
+
" query,",
|
15 |
+
"} from \"./_generated/server\";"
|
16 |
+
],
|
17 |
+
"scope": "javascript,typescript",
|
18 |
+
"isFileTemplate": true
|
19 |
+
},
|
20 |
+
|
21 |
+
"Convex Query": {
|
22 |
+
"prefix": "convex:query",
|
23 |
+
"body": [
|
24 |
+
"export const $1 = query({",
|
25 |
+
" args: {},",
|
26 |
+
" handler: async (ctx, args) => {",
|
27 |
+
" $0",
|
28 |
+
" },",
|
29 |
+
"});"
|
30 |
+
],
|
31 |
+
"scope": "javascript,typescript"
|
32 |
+
},
|
33 |
+
|
34 |
+
"Convex Internal Query": {
|
35 |
+
"prefix": "convex:internalQuery",
|
36 |
+
"body": [
|
37 |
+
"export const $1 = internalQuery({",
|
38 |
+
" args: {},",
|
39 |
+
" handler: async (ctx, args) => {",
|
40 |
+
" $0",
|
41 |
+
" },",
|
42 |
+
"});"
|
43 |
+
],
|
44 |
+
"scope": "javascript,typescript"
|
45 |
+
},
|
46 |
+
|
47 |
+
"Convex Mutation": {
|
48 |
+
"prefix": "convex:mutation",
|
49 |
+
"body": [
|
50 |
+
"export const $1 = mutation({",
|
51 |
+
" args: {},",
|
52 |
+
" handler: async (ctx, args) => {",
|
53 |
+
" $0",
|
54 |
+
" },",
|
55 |
+
"});"
|
56 |
+
],
|
57 |
+
"scope": "javascript,typescript"
|
58 |
+
},
|
59 |
+
|
60 |
+
"Convex Internal Mutation": {
|
61 |
+
"prefix": "convex:internalMutation",
|
62 |
+
"body": [
|
63 |
+
"export const $1 = internalMutation({",
|
64 |
+
" args: {},",
|
65 |
+
" handler: async (ctx, args) => {",
|
66 |
+
" $0",
|
67 |
+
" },",
|
68 |
+
"});"
|
69 |
+
],
|
70 |
+
"scope": "javascript,typescript"
|
71 |
+
},
|
72 |
+
|
73 |
+
"Convex Action": {
|
74 |
+
"prefix": "convex:action",
|
75 |
+
"body": [
|
76 |
+
"import { action } from \"./_generated/server\";",
|
77 |
+
"",
|
78 |
+
"export const $1 = action({",
|
79 |
+
" args: {},",
|
80 |
+
" handler: async (ctx, args) => {",
|
81 |
+
" $0",
|
82 |
+
" },",
|
83 |
+
"});"
|
84 |
+
],
|
85 |
+
"scope": "javascript,typescript"
|
86 |
+
},
|
87 |
+
|
88 |
+
"Convex Internal Action": {
|
89 |
+
"prefix": "convex:internalAction",
|
90 |
+
"body": [
|
91 |
+
"import { internalAction } from \"./_generated/server\";",
|
92 |
+
"",
|
93 |
+
"export const $1 = internalAction({",
|
94 |
+
" args: {},",
|
95 |
+
" handler: async (ctx, args) => {",
|
96 |
+
" $0",
|
97 |
+
" },",
|
98 |
+
"});"
|
99 |
+
],
|
100 |
+
"scope": "javascript,typescript"
|
101 |
+
}
|
102 |
+
}
|
.vscode/settings.json
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"editor.formatOnSave": true,
|
3 |
+
"editor.tabSize": 2,
|
4 |
+
"[html]": {
|
5 |
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
6 |
+
},
|
7 |
+
"[javascript]": {
|
8 |
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
9 |
+
},
|
10 |
+
"[jsonc]": {
|
11 |
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
12 |
+
},
|
13 |
+
"[typescript]": {
|
14 |
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
15 |
+
},
|
16 |
+
"[typescriptreact]": {
|
17 |
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
18 |
+
},
|
19 |
+
"typescript.preferences.importModuleSpecifierEnding": "auto",
|
20 |
+
"javascript.preferences.importModuleSpecifierEnding": "auto"
|
21 |
+
}
|
ARCHITECTURE.md
ADDED
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Architecture
|
2 |
+
|
3 |
+
This documents dives into the high-level architecture of AI Town and its different layers. We'll
|
4 |
+
first start with a brief overview and then go in-depth on each component. The overview should
|
5 |
+
be sufficient for forking AI Town and changing game or agent behavior. Read on to the deep dives
|
6 |
+
if you're interested or running up against the engine's limitations.
|
7 |
+
|
8 |
+
This doc assumes the reader has a working knowledge of Convex. If you're new to Convex, check out
|
9 |
+
the [Convex tutorial](https://docs.convex.dev/get-started) to get started.
|
10 |
+
|
11 |
+
## Overview
|
12 |
+
|
13 |
+
AI Town is split into a few layers:
|
14 |
+
|
15 |
+
- The server-side game logic in `convex/aiTown`: This layer defines what state AI Town maintains,
|
16 |
+
how it evolves over time, and how it reacts to user input. Both humans and agents submit inputs
|
17 |
+
that the game engine processes.
|
18 |
+
- The client-side game UI in `src/`: AI Town uses `pixi-react` to render the game state to the
|
19 |
+
browser for human consumption.
|
20 |
+
- The game engine in `convex/engine`: To make it easy to hack on the game rules, we've separated
|
21 |
+
out the game engine from the AI Town-specific game rules. The game engine is responsible for
|
22 |
+
saving and loading game state from the database, coordinating feeding inputs into the engine,
|
23 |
+
and actually running the game engine in Convex functions.
|
24 |
+
- The agent in `convex/agent`: Agents run as part of the game loop, and can kick off asynchronous
|
25 |
+
Convex functions to do longer processing, such as talking to LLMs. Those functions can save state
|
26 |
+
in separate tables, or submit inputs to the game engine to modify game state. Internally, our
|
27 |
+
agents use a combination of simple rule-based systems and talking to an LLM.
|
28 |
+
|
29 |
+
So, if you'd like to tweak agent behavior but keep the same game mechanics, check out `convex/agent`
|
30 |
+
for the async work, and `convex/aiTown/agent.ts` for the game loop logic.
|
31 |
+
If you would like to add new gameplay elements (that both humans and agents can interact with), add
|
32 |
+
the feature to `convex/aiTown`, render it in the UI in `src/`, and respond to it in `convex/aiTown/agent.ts`.
|
33 |
+
|
34 |
+
If you have parts of your game that are more latency sensitive, you can move them out of engine
|
35 |
+
into regular Convex tables, queries, and mutations, only logging key bits into game state. See
|
36 |
+
"Message data model" below for an example.
|
37 |
+
|
38 |
+
## AI Town game logic (`convex/aiTown`)
|
39 |
+
|
40 |
+
### Data model
|
41 |
+
|
42 |
+
AI Town's data model has a few concepts:
|
43 |
+
|
44 |
+
- Worlds (`convex/aiTown/world.ts`) represent a map with many players interacting together.
|
45 |
+
- Players (`convex/aiTown/player.ts`) are the core characters in the game. Players have human readable names and
|
46 |
+
descriptions, and they may be associated with a human user. At any point in time, a player may be pathfinding
|
47 |
+
towards some destination and has a current location.
|
48 |
+
- Conversations (`convex/aiTown/conversations.ts`) are created by a player and end at some point in time.
|
49 |
+
- Conversation memberships (`convex/aiTown/conversationMembership.ts`) indicate that a player is a member
|
50 |
+
of a conversation. Players may only be in one conversation at any point in time, and conversations
|
51 |
+
currently have exactly two members. Memberships may be in one of three states:
|
52 |
+
- `invited`: The player has been invited to the conversation but hasn't accepted yet.
|
53 |
+
- `walkingOver`: The player has accepted the invite to the conversation but is too far away to talk. The
|
54 |
+
player will automatically join the conversation when they get close enough.
|
55 |
+
- `participating`: The player is actively participating in the conversation.
|
56 |
+
|
57 |
+
### Schema
|
58 |
+
|
59 |
+
There are three main categories of tables:
|
60 |
+
|
61 |
+
1. Engine tables (`convex/engine/schema.ts`) for maintaining engine-internal state.
|
62 |
+
2. Game tables (`convex/aiTown/schema.ts`) for game state. To keep game state small and efficient to
|
63 |
+
read and write, we store AI Town's data model across a few tables. See `convex/aiTown/schema.ts` for an overview.
|
64 |
+
3. Agent tables (`convex/agent/schema.ts`) for agent state. Agents can freely read and write to these tables
|
65 |
+
within their actions.
|
66 |
+
|
67 |
+
### Inputs (`convex/aiTown/inputs.ts`)
|
68 |
+
|
69 |
+
AI Town modifies its data model by processing inputs. Inputs are submitted by players and agents and
|
70 |
+
processed by the game engine. We specify inputs in the `inputs` object in `convex/aiTown/inputs.ts`.
|
71 |
+
Use the `inputHandler` function to construct an input handler, specifying a Convex validator for
|
72 |
+
arguments for end-to-end type-safety.
|
73 |
+
|
74 |
+
- Joining (`join`) and leaving (`leave`) the game.
|
75 |
+
- Moving a player to a particular location (`moveTo`): Movement in AI Town is similar to RTS games, where
|
76 |
+
the players specify where they want to go, and the engine figures out how to get there.
|
77 |
+
- Starting a conversation (`startConversation`), accepting an invite (`acceptInvite`), rejecting an invite
|
78 |
+
(`rejectInvite`), and leaving a conversation (`leaveConversation`). To track typing indicators,
|
79 |
+
you use `startTyping` and `finishSendingMessage`. These are imported from `game/conversations.ts`.
|
80 |
+
- Agent inputs are imported from `aiTown/agentInputs.ts` for things like remembering conversations,
|
81 |
+
deciding what to do, etc.
|
82 |
+
|
83 |
+
Each of these inputs' implementation method checks invariants and updates game state as desired.
|
84 |
+
For example, the `moveTo` input checks that the player isn't participating in a conversation,
|
85 |
+
throwing an error telling them to leave the conversation first if so, and then updates their
|
86 |
+
pathfinding state with the desired destination.
|
87 |
+
|
88 |
+
### Simulation
|
89 |
+
|
90 |
+
Other than when processing player inputs, the game state can change over time in the background as the
|
91 |
+
simulation runs time forward. For example, if a player has decided to move along a path, their position
|
92 |
+
will gradually update as time moves forward. Similarly, if two players collide into each other, they'll
|
93 |
+
notice and replan their paths, trying to avoid obstacles.
|
94 |
+
|
95 |
+
### Message data model
|
96 |
+
|
97 |
+
We manage the tables for tracking chat messages in separate tables not affiliated
|
98 |
+
with the game engine. This is for a few reasons:
|
99 |
+
|
100 |
+
- The core simulation doesn't need to know about messages, so keeping them
|
101 |
+
out keeps game state small.
|
102 |
+
- Messages are updated very frequently (when streamed out from OpenAI) and
|
103 |
+
benefit from lower input latency, so they're not a great fit for the engine.
|
104 |
+
See "Design goals and limitations" below.
|
105 |
+
|
106 |
+
Messages (`convex/schema.ts`) are in a conversation and indicate an author and message text.
|
107 |
+
Each conversation has a typing state in the conversations table that indicates that a player
|
108 |
+
is currently typing. Players can still send messages while another player is typing, but
|
109 |
+
having the indicator helps agents (and humans) not talk over each other.
|
110 |
+
|
111 |
+
The separate tables are queried and modified with regular Convex queries and mutations
|
112 |
+
that don't directly go through the simulation.
|
113 |
+
|
114 |
+
## Game engine (`convex/engine`)
|
115 |
+
|
116 |
+
Given the description of AI Town's game behavior in the previous section,
|
117 |
+
the `AbstractGame` class in `convex/engine/abstractGame.ts` implements actually running the simulation.
|
118 |
+
The game engine has a few responsibilities:
|
119 |
+
|
120 |
+
- Coordinating incoming player inputs, feeding them into the simulation, and sending their
|
121 |
+
return values (or errors) to the client.
|
122 |
+
- Running the simulation forward in time.
|
123 |
+
- Saving and loading game state from the database.
|
124 |
+
- Managing executing the game behavior, efficiently using Convex resources and minimizing input latency.
|
125 |
+
|
126 |
+
AI Town's game behavior is implemented in the `Game` subclass.
|
127 |
+
|
128 |
+
### Input handling
|
129 |
+
|
130 |
+
Users submit inputs through the `insertInput` function, which inserts them into an `inputs` table, assigning a
|
131 |
+
monotonically increasing unique input number and stamping the input with the time the server received it. The
|
132 |
+
engine then processes inputs, writing their results back to the `inputs` row. Interested clients can subscribe
|
133 |
+
on an input's status with the `inputStatus` query.
|
134 |
+
|
135 |
+
`Game` provides an abstract method `handleInput` that `AiTown` implements with its specific behavior.
|
136 |
+
|
137 |
+
### Running the simulation
|
138 |
+
|
139 |
+
The `Game` class specifies how it simulates time forward with the `tick` method:
|
140 |
+
|
141 |
+
- `tick(now)` runs the simulation forward until the given timestamp
|
142 |
+
- Ticks are run at a high frequency, configurable with `tickDuration` (milliseconds). Since AI town has smooth motion
|
143 |
+
for player movement, it runs at 60 ticks per second.
|
144 |
+
- It's generally a good idea to break up game logic into separate systems that can be ticked forward independently.
|
145 |
+
For example, AI Town's `tick` method advances pathfinding with `Player.tickPathfinding`, player positions with
|
146 |
+
`Player.tickPosition`, conversations with `Conversation.tick`, and `Agent.tick` for agent logic.
|
147 |
+
|
148 |
+
To avoid running a Convex mutation 60 times per second (which would be expensive and slow), the engine batches up
|
149 |
+
many ticks into a _step_. AI town runs steps at only 1 time per second. Here's how a step works:
|
150 |
+
|
151 |
+
1. Load the game state into memory.
|
152 |
+
2. Decide how long to run.
|
153 |
+
3. Execute many ticks for our time interval, alternating between feeding in inputs with `handleInput` and advancing
|
154 |
+
the simulation with `tick`.
|
155 |
+
4. Write the updated game state back to the database.
|
156 |
+
|
157 |
+
One core invariant is that the game engine is fully "single-threaded" per world, so there are never two runs of
|
158 |
+
an engine's step overlapping in time. Not having to think about race conditions or concurrency makes writing game
|
159 |
+
engine code a lot easier.
|
160 |
+
|
161 |
+
However, preserving this invariant is a little tricky. If the engine is idle for a minute and an
|
162 |
+
input comes in, we want to run the engine immediately but then cancel its run after the minute's
|
163 |
+
up. If we're not careful, a race condition may cause us to run multiple copies of the engine if an
|
164 |
+
input comes in just as an idle timeout is expiring!
|
165 |
+
|
166 |
+
Our approach is to store a generation number with the engine that monotonically increases over time.
|
167 |
+
All scheduled runs of the engine contain their expected generation number as an argument. Then, if
|
168 |
+
we'd like to cancel a future run of the engine, we can bump the generation number by one, and then
|
169 |
+
we're guaranteed that the subsequent run will fail immediately as it'll notice that the engine's
|
170 |
+
generation number does not match its expected one.
|
171 |
+
|
172 |
+
### Engine state management
|
173 |
+
|
174 |
+
The `World`, `Player`, `Conversation`, and `Agent` classes coordinate loading data into memory from the database,
|
175 |
+
modifying it according to the game rules, and serializing it to write back out to the database. Here's the flow:
|
176 |
+
|
177 |
+
1. The Convex scheduler calls the `convex/aiTown/main.ts:runStep` action.
|
178 |
+
2. The `runStep` action calls `convex/aiTown/game.ts:loadWorld` to load the current game state. This query calls
|
179 |
+
`Game.load`, which loads all of a world's game state from the appropriate tables, and returns a
|
180 |
+
`GameState` object, which contains serialized versions of all of the players, agents, etc.
|
181 |
+
3. The `runStep` action passes the `GameState` to the `Game` constructor, which parses the serialized versions
|
182 |
+
of all our game objects using their constructors. For example, `new Player(serializedPlayer)` parses the
|
183 |
+
database representation into the in-memory `Player` class.
|
184 |
+
4. The engine runs the simulation, modifying the in-memory game objects.
|
185 |
+
5. At the end of a step, the framework calls `Game.saveStep`, which computes a diff of the game state since
|
186 |
+
the beginning of the step and passes the diff to the `convex/aiTown/game.ts:saveWorld` mutation.
|
187 |
+
6. The `saveWorld` mutation applies the diff to the database, notices if any deleted objects need to be archived,
|
188 |
+
updates the `participatedTogether` graph, and kicks off any scheduled jobs to run.
|
189 |
+
7. Since the engine is the only mutator of game state, it continues to run steps for some amount of time
|
190 |
+
without repeating steps 1 to 3 again.
|
191 |
+
|
192 |
+
Just as we assume that the game engine is "single threaded", we also assume that the game engine _exclusively_
|
193 |
+
owns the tables that store game engine state. Only the game engine should programmatically modify these tables,
|
194 |
+
so components outside the engine can only mutate them by sending inputs.
|
195 |
+
|
196 |
+
### Historical tables
|
197 |
+
|
198 |
+
If we're only writing updates out to the database at the end of the step, and steps are only running at once per
|
199 |
+
second, continuous quantities like position will only update every second. This, then, defeats the whole purpose
|
200 |
+
of having high-frequency ticks: Player positions will jump around and look choppy.
|
201 |
+
|
202 |
+
To solve this, we track the historical values of quantities like position _within_ a step, storing the value
|
203 |
+
at the end of each tick. Then, the client receives both the current value _and_ the past step's worth of
|
204 |
+
history, and it can "replay" the history to make the motion smooth.
|
205 |
+
|
206 |
+
The game tracks these quantities at the end of each tick by feeding them to a `HistoricalObject`. This object
|
207 |
+
efficiently tracks its changes over time and serializes them into a buffer that clients can use for replaying
|
208 |
+
its history. There are a few limitations on `HistoricalObject`:
|
209 |
+
|
210 |
+
- Historical objects can only have numeric (floating point) values and can't have nested objects or optional fields.
|
211 |
+
- Historical objects must declare which fields they'd like to track.
|
212 |
+
|
213 |
+
We store each player's "location" (i.e. its position, orientation, and speed) in a `HistoricalObject` and
|
214 |
+
write it to the `worlds` document at the end of a step when computing a diff.
|
215 |
+
|
216 |
+
## Client-side game UI (`src/`)
|
217 |
+
|
218 |
+
One guiding principle for AI Town's architecture is to keep the usage as close to "regular Convex" usage as possible. So,
|
219 |
+
game state is stored in regular tables, and the UI just uses regular `useQuery` hooks to load that state and render
|
220 |
+
it in the UI.
|
221 |
+
|
222 |
+
The one exception is for historical tables, which feed in the latest state into a `useHistoricalValue` hook that parses
|
223 |
+
the history buffer and replays time forward for smooth motion. To keep replayed time synchronized across multiple
|
224 |
+
historical buffers, we provide a `useHistoricalTime` hook for the top of your app that keeps track of the current
|
225 |
+
time and returns it for you to pass down into components.
|
226 |
+
|
227 |
+
We also provide a `useSendInput` hook that wraps `useMutation` and automatically sends inputs to the server and
|
228 |
+
waits for the engine to process them and return their outcome.
|
229 |
+
|
230 |
+
## Agent architecture (`convex/agent`)
|
231 |
+
|
232 |
+
### The agent loop (`convex/game/agents.ts`)
|
233 |
+
|
234 |
+
Agents will execute any game state changes, and schedule operations to do anything that requires
|
235 |
+
a long-lived request or accessing non-game tables. The flow generally is:
|
236 |
+
|
237 |
+
1. Logic in `Agent.tick` can read and modify game state as time progresses, such as waiting until
|
238 |
+
the agent is near another player to start talking.
|
239 |
+
2. When there is something that needs to talk to an LLM or read/write external data,
|
240 |
+
it calls `startOperation` with a reference to a Convex function: generally an `internalAction`.
|
241 |
+
3. This function can read state from game tables and other tables via `internalQuery` functions.
|
242 |
+
4. It executes long-running tasks, and can write data via `internalMutation`s.
|
243 |
+
Game state should not be written, but rather submitted via `inputs` (described in a previous section).
|
244 |
+
5. Inputs are submitted from actions with `ctx.runMutation(api.game.main.sendInput, {...})` from actions
|
245 |
+
or via `insertInput` from mutations. They are referenced by their name as a string, like `moveTo`.
|
246 |
+
6. Inputs are defined with `inputHandler` and are given an instance of the AiTown game to modify,
|
247 |
+
similar to the game loop. In fact, these are called as part of the game loop before `tickAgent`.
|
248 |
+
7. When an operation is done, it deletes the `inProgressOperation`. This is to ensure an agent only
|
249 |
+
is trying to do one thing at a time.
|
250 |
+
8. `Agent.tick` then can observe the new game state and continue to make decisions.
|
251 |
+
|
252 |
+
### Conversations (`convex/agent/conversations.ts`)
|
253 |
+
|
254 |
+
The agent code calls into the conversation layer which implements the prompt engineering for
|
255 |
+
injecting personality and memories into the GPT responses. It has functions for starting a
|
256 |
+
conversation (`startConversation`), continuing after the first message (`continueConversation`), and
|
257 |
+
politely leaving a conversation (`leaveConversation`). Each function loads structured data from the
|
258 |
+
database, queries the memory layer for the agent's opinion about the player they're talking with,
|
259 |
+
and then calls into the OpenAI client (`convex/util/openai.ts`).
|
260 |
+
|
261 |
+
### Memories (`convex/agent/memory.ts`)
|
262 |
+
|
263 |
+
After each conversation, GPT summarizes its message history, and we compute an embedding of the
|
264 |
+
summary text and write it into Convex's vector database. Then, when starting a new conversation
|
265 |
+
with, Danny, we embed "What you think about Danny?", find the three most similar memories, and fetch
|
266 |
+
their summary texts to inject into the conversation prompt.
|
267 |
+
|
268 |
+
### Embeddings cache (`convex/agent/embeddingsCache.ts`)
|
269 |
+
|
270 |
+
To avoid computing the same embedding over and over again, we cache embeddings by a hash of their
|
271 |
+
text in a Convex table.
|
272 |
+
|
273 |
+
## Design goals and limitations
|
274 |
+
|
275 |
+
AI Town's game engine has a few design goals:
|
276 |
+
|
277 |
+
- Try to be as close to a regular Convex app as possible. Use regular client hooks (like `useQuery`)
|
278 |
+
when possible, and store game state in regular tables.
|
279 |
+
- Be as similar to existing engines as possible, so it's easy to change the behavior. We chose a
|
280 |
+
`tick()` based model for simulation since it's commonly used elsewhere and intuitive.
|
281 |
+
- Decouple agent behavior from the game engine. It's nice to allow human players and AI agents to do
|
282 |
+
all the same things in the game.
|
283 |
+
|
284 |
+
These design goals imply some inherent limitations:
|
285 |
+
|
286 |
+
- All data is loaded into memory each step. The active game state loaded by the game should be small
|
287 |
+
enough to fit into memory and load and save frequently. Try to keep game state to less than a few dozen
|
288 |
+
kilobytes: Games that require tens of thousands of objects interacting together may not be a good
|
289 |
+
fit.
|
290 |
+
- All inputs are fed through the database in the `inputs` table, so applications that require very
|
291 |
+
large or frequent inputs may not be a good fit.
|
292 |
+
- Input latency will be around one RTT (time for the input to make it to the server and the response
|
293 |
+
to come back) plus half the step size (for expected server input delay when the input's waiting
|
294 |
+
for the next step). Historical values add another half step size of input latency since their
|
295 |
+
values are viewed slightly in the past. As configured, this will roughly be around 1.5s of input
|
296 |
+
latency, which won't be a good fit for competitive games. You can configure the step size to be
|
297 |
+
smaller (e.g. 250ms) which will decrease input latency at the cost of adding more Convex function
|
298 |
+
calls and database bandwidth.
|
299 |
+
- The game engine is designed to be single threaded. JavaScript operating over plain objects
|
300 |
+
in-memory can be surprisingly fast, but if your simulation is very computationally expensive, it
|
301 |
+
may not be a good fit on AI Town's engine today.
|
Dockerfile
CHANGED
@@ -17,10 +17,6 @@ ENV HOME=/home/user \
|
|
17 |
PATH=/home/user/.local/bin:$PATH
|
18 |
|
19 |
WORKDIR $HOME/app
|
20 |
-
|
21 |
-
RUN git clone https://github.com/a16z-infra/ai-town.git . && \
|
22 |
-
git checkout f005c46d1759b47bb3ade8d41952a713c4faf331
|
23 |
-
|
24 |
RUN npm install --include=dev @huggingface/inference
|
25 |
RUN npm install --include=dev @huggingface/hub
|
26 |
|
@@ -28,17 +24,4 @@ RUN npm install --include=dev @huggingface/hub
|
|
28 |
RUN curl -L -O https://github.com/get-convex/convex-backend/releases/download/precompiled-2024-05-07-13337fd/convex-local-backend-x86_64-unknown-linux-gnu.zip && \
|
29 |
unzip convex-local-backend-x86_64-unknown-linux-gnu.zip
|
30 |
|
31 |
-
COPY ./patches ./
|
32 |
-
COPY ./patches/vite.config.ts ./
|
33 |
-
COPY ./patches/characters.ts ./patches/gentle.js ./data/
|
34 |
-
COPY ./patches/run.sh ./
|
35 |
-
|
36 |
-
COPY ./map.png ./assets/map.png
|
37 |
-
COPY ./patches/assets/GrayCat.png ./assets/GrayCat.png
|
38 |
-
COPY ./patches/assets/OrangeCat.png ./assets/OrangeCat.png
|
39 |
-
COPY ./patches/assets/hf.svg ./assets/hf.svg
|
40 |
-
COPY ./patches/data/spritesheets/c1.ts ./data/spritesheets/c1.ts
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
CMD ["./run.sh"]
|
|
|
17 |
PATH=/home/user/.local/bin:$PATH
|
18 |
|
19 |
WORKDIR $HOME/app
|
|
|
|
|
|
|
|
|
20 |
RUN npm install --include=dev @huggingface/inference
|
21 |
RUN npm install --include=dev @huggingface/hub
|
22 |
|
|
|
24 |
RUN curl -L -O https://github.com/get-convex/convex-backend/releases/download/precompiled-2024-05-07-13337fd/convex-local-backend-x86_64-unknown-linux-gnu.zip && \
|
25 |
unzip convex-local-backend-x86_64-unknown-linux-gnu.zip
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
CMD ["./run.sh"]
|
Justfile
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
set fallback := true
|
2 |
+
set shell := ["bash", "-uc"]
|
3 |
+
set windows-shell := ["sh", "-uc"]
|
4 |
+
|
5 |
+
# `just --list` (or just `just`) will print all the recipes in
|
6 |
+
# the current Justfile. `just RECIPE` will run the macro/job.
|
7 |
+
#
|
8 |
+
# In several places there are recipes for running common scripts or commands.
|
9 |
+
# Instead of `Makefile`s, Convex uses Justfiles, which are similar, but avoid
|
10 |
+
# several footguns associated with Makefiles, since using make as a macro runner
|
11 |
+
# can sometimes conflict with Makefiles desire to have some rudimentary
|
12 |
+
# understanding of build artifacts and associated dependencies.
|
13 |
+
#
|
14 |
+
# Read up on just here: https://github.com/casey/just
|
15 |
+
|
16 |
+
_default:
|
17 |
+
@just --list
|
18 |
+
|
19 |
+
set positional-arguments
|
20 |
+
|
21 |
+
# Uses an admin key from admin_key.txt for dev backends.
|
22 |
+
# This uses the default admin key for local backends, which is safe as long as the backend is
|
23 |
+
# running locally.
|
24 |
+
# (*) Run convex CLI commands like `convex dev` against local backend from `just run-local-backend`.
|
25 |
+
convex *ARGS:
|
26 |
+
cd {{invocation_directory()}}; npx convex "$@" --admin-key 0135d8598650f8f5cb0f30c34ec2e2bb62793bc28717c8eb6fb577996d50be5f4281b59181095065c5d0f86a2c31ddbe9b597ec62b47ded69782cd --url "http://127.0.0.1:3210"
|
27 |
+
|
28 |
+
# Clears any data or stored files from the local backend.
|
29 |
+
reset-local-backend:
|
30 |
+
rm -rf convex_local_storage && rm -f convex_local_backend.sqlite3
|
LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2023 a16z-infra
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
README.md
CHANGED
@@ -1,36 +1,445 @@
|
|
1 |
-
|
2 |
-
title: AI Town on HuggingFace
|
3 |
-
emoji: π πββ¬
|
4 |
-
colorFrom: green
|
5 |
-
colorTo: red
|
6 |
-
sdk: docker
|
7 |
-
app_port: 5173
|
8 |
-
pinned: false
|
9 |
-
disable_embedding: true
|
10 |
-
# header: mini
|
11 |
-
short_description: AI Town on HuggingFace
|
12 |
-
hf_oauth: true
|
13 |
-
---
|
14 |
|
15 |
-
|
16 |
|
17 |
-
[
|
18 |
|
19 |
-
|
20 |
|
21 |
-
|
22 |
|
23 |
-
|
|
|
24 |
|
25 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
```bash
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
```
|
32 |
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
|
36 |
-
Then you can customize [patches/constants.ts](patches/constants.ts) and [patches/characters.ts](patches/characters.ts) as you wish, as well as the LLM model and embeddings model in [patches/llm.ts](patches/llm.ts).
|
|
|
1 |
+
# AI Town π π»π
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
+
[Live Demo](https://www.convex.dev/ai-town)
|
4 |
|
5 |
+
[Join our community Discord: AI Stack Devs](https://discord.gg/PQUmTBTGmT)
|
6 |
|
7 |
+
<img width="1454" alt="Screen Shot 2023-08-14 at 10 01 00 AM" src="https://github.com/a16z-infra/ai-town/assets/3489963/a4c91f17-23ed-47ec-8c4e-9f9a8505057d">
|
8 |
|
9 |
+
AI Town is a virtual town where AI characters live, chat and socialize.
|
10 |
|
11 |
+
This project is a deployable starter kit for easily building and customizing your own version of AI town.
|
12 |
+
Inspired by the research paper [_Generative Agents: Interactive Simulacra of Human Behavior_](https://arxiv.org/pdf/2304.03442.pdf).
|
13 |
|
14 |
+
The primary goal of this project, beyond just being a lot of fun to work on,
|
15 |
+
is to provide a platform with a strong foundation that is meant to be extended.
|
16 |
+
The back-end natively supports shared global state, transactions, and a simulation engine
|
17 |
+
and should be suitable from everything from a simple project to play around with to a scalable, multi-player game.
|
18 |
+
A secondary goal is to make a JS/TS framework available as most simulators in this space
|
19 |
+
(including the original paper above) are written in Python.
|
20 |
+
|
21 |
+
## Overview
|
22 |
+
|
23 |
+
- π» [Stack](#stack)
|
24 |
+
- π§ [Installation](#installation)
|
25 |
+
- π€ [Customize - run YOUR OWN simulated world](#customize-your-own-simulation)
|
26 |
+
- π©βπ» [Deploying](#deploy-the-app)
|
27 |
+
- π [Credits](#credits)
|
28 |
+
|
29 |
+
## Stack
|
30 |
+
|
31 |
+
- Game engine, database, and vector search: [Convex](https://convex.dev/)
|
32 |
+
- Auth (Optional): [Clerk](https://clerk.com/)
|
33 |
+
- Default chat model is `llama3` and embeddings with `mxbai-embed-large`.
|
34 |
+
- Local inference: [Ollama](https://github.com/jmorganca/ollama)
|
35 |
+
- Configurable for other cloud LLMs: [Together.ai](https://together.ai/) or anything
|
36 |
+
that speaks the [OpenAI API](https://platform.openai.com/).
|
37 |
+
PRs welcome to add more cloud provider support.
|
38 |
+
- Pixel Art Generation: [Replicate](https://replicate.com/), [Fal.ai](https://serverless.fal.ai/lora)
|
39 |
+
- Background Music Generation: [Replicate](https://replicate.com/) using [MusicGen](https://huggingface.co/spaces/facebook/MusicGen)
|
40 |
+
|
41 |
+
## Installation
|
42 |
+
|
43 |
+
**Note**: There is a one-click install of a fork of this project on
|
44 |
+
[Pinokio](https://pinokio.computer/item?uri=https://github.com/cocktailpeanutlabs/aitown)
|
45 |
+
for anyone interested in running but not modifying it π
|
46 |
+
|
47 |
+
### 1. Clone repo and Install packages
|
48 |
+
|
49 |
+
```bash
|
50 |
+
git clone https://github.com/a16z-infra/ai-town.git
|
51 |
+
cd ai-town
|
52 |
+
npm install
|
53 |
+
```
|
54 |
+
|
55 |
+
### 2. To develop locally with [Convex](https://convex.dev):
|
56 |
+
|
57 |
+
Either
|
58 |
+
[download a pre-built binary(recommended)](https://github.com/get-convex/convex-backend/releases),
|
59 |
+
or [build it from source and run it](https://stack.convex.dev/building-the-oss-backend).
|
60 |
+
|
61 |
+
```sh
|
62 |
+
# For new Macs:
|
63 |
+
curl -L -O https://github.com/get-convex/convex-backend/releases/latest/download/convex-local-backend-aarch64-apple-darwin.zip
|
64 |
+
unzip convex-local-backend-aarch64-apple-darwin.zip
|
65 |
+
|
66 |
+
brew install just
|
67 |
+
|
68 |
+
# Runs the server
|
69 |
+
./convex-local-backend
|
70 |
+
```
|
71 |
+
|
72 |
+
This also [installs `just`](https://github.com/casey/just?tab=readme-ov-file#installation)
|
73 |
+
(e.g. `brew install just` or `cargo install just`).
|
74 |
+
We use `just` like `make` to add extra params, so you run `just convex ...`
|
75 |
+
instead of `npx convex ...` for local development.
|
76 |
+
|
77 |
+
If you're running the pre-built binary on Mac and there's an Apple warning,
|
78 |
+
go to the folder it's in and right-click it and select "Open" to bypass.
|
79 |
+
From then on you can run it from the commandline.
|
80 |
+
Or you can compile it from source and run it (see above).
|
81 |
+
|
82 |
+
To develop against the cloud-hosted version, change the package.json scripts
|
83 |
+
to use `convex ...` instead of `just convex ...`.
|
84 |
+
|
85 |
+
### 3. To run a local LLM, download and run [Ollama](https://ollama.com/).
|
86 |
+
|
87 |
+
You can leave the app running or run `ollama serve`.
|
88 |
+
`ollama serve` will warn you if the app is already running.
|
89 |
+
Run `ollama pull llama3` to have it download `llama3`.
|
90 |
+
Test it out with `ollama run llama3`.
|
91 |
+
If you want to customize which model to use, adjust convex/util/llm.ts or set
|
92 |
+
`just convex env set LLM_MODEL # model`.
|
93 |
+
Ollama model options can be found [here](https://ollama.ai/library).
|
94 |
+
|
95 |
+
You might want to set `NUM_MEMORIES_TO_SEARCH` to `1` in constants.ts,
|
96 |
+
to reduce the size of conversation prompts, if you see slowness.
|
97 |
+
|
98 |
+
Check out `convex/config.ts` to configure which models to offer to the UI,
|
99 |
+
or to set it up to talk to a cloud-hosted LLM.
|
100 |
+
|
101 |
+
### 4. Adding background music with Replicate (Optional)
|
102 |
+
|
103 |
+
For Daily background music generation, create a
|
104 |
+
[Replicate](https://replicate.com/) account and create a token in your Profile's
|
105 |
+
[API Token page](https://replicate.com/account/api-tokens).
|
106 |
+
`npx convex env set REPLICATE_API_TOKEN # token`
|
107 |
+
Specify `just` instead of `npx` if you're doing local development.
|
108 |
+
|
109 |
+
### 5. Run the code
|
110 |
+
|
111 |
+
To run both the front and and back end:
|
112 |
+
|
113 |
+
```bash
|
114 |
+
npm run dev
|
115 |
+
```
|
116 |
+
|
117 |
+
**Note**: If you encounter a node version error on the convex server upon application startup, please use node version 18, which is the most stable. One way to do this is by [installing nvm](https://nodejs.org/en/download/package-manager) and running `nvm install 18` or `nvm use 18`. Do this before both the `npm run dev` above and the `./convex-local-backend` in Step 2.
|
118 |
+
|
119 |
+
You can now visit http://localhost:5173.
|
120 |
+
|
121 |
+
If you'd rather run the frontend in a separate terminal from Convex (which syncs
|
122 |
+
your backend functions as they're saved), you can run these two commands:
|
123 |
+
|
124 |
+
```bash
|
125 |
+
npm run dev:frontend
|
126 |
+
npm run dev:backend
|
127 |
+
```
|
128 |
+
|
129 |
+
See package.json for details, but dev:backend runs `just convex dev`
|
130 |
+
|
131 |
+
**Note**: The simulation will pause after 5 minutes if the window is idle.
|
132 |
+
Loading the page will unpause it.
|
133 |
+
You can also manually freeze & unfreeze the world with a button in the UI.
|
134 |
+
If you want to run the world without the
|
135 |
+
browser, you can comment-out the "stop inactive worlds" cron in `convex/crons.ts`.
|
136 |
+
|
137 |
+
### Various commands to run / test / debug
|
138 |
+
|
139 |
+
**To stop the back end, in case of too much activity**
|
140 |
+
|
141 |
+
This will stop running the engine and agents. You can still run queries and
|
142 |
+
run functions to debug.
|
143 |
+
|
144 |
+
```bash
|
145 |
+
just convex run testing:stop
|
146 |
+
```
|
147 |
+
|
148 |
+
**To restart the back end after stopping it**
|
149 |
+
|
150 |
+
```bash
|
151 |
+
just convex run testing:resume
|
152 |
+
```
|
153 |
+
|
154 |
+
**To kick the engine in case the game engine or agents aren't running**
|
155 |
+
|
156 |
+
```bash
|
157 |
+
just convex run testing:kick
|
158 |
+
```
|
159 |
+
|
160 |
+
**To archive the world**
|
161 |
+
|
162 |
+
If you'd like to reset the world and start from scratch, you can archive the current world:
|
163 |
|
164 |
```bash
|
165 |
+
just convex run testing:archive
|
166 |
+
```
|
167 |
+
|
168 |
+
Then, you can still look at the world's data in the dashboard, but the engine and agents will
|
169 |
+
no longer run.
|
170 |
+
|
171 |
+
You can then create a fresh world with `init`.
|
172 |
+
|
173 |
+
```bash
|
174 |
+
just convex run init
|
175 |
+
```
|
176 |
+
|
177 |
+
**To clear all databases**
|
178 |
+
|
179 |
+
You can wipe all tables with the `wipeAllTables` testing function.
|
180 |
+
|
181 |
+
```bash
|
182 |
+
just convex run testing:wipeAllTables
|
183 |
+
```
|
184 |
+
|
185 |
+
**To pause your backend deployment**
|
186 |
+
|
187 |
+
You can go to the [dashboard](https://dashboard.convex.dev) to your deployment
|
188 |
+
settings to pause and un-pause your deployment. This will stop all functions, whether invoked
|
189 |
+
from the client, scheduled, or as a cron job. See this as a last resort, as
|
190 |
+
there are gentler ways of stopping above. Once you
|
191 |
+
|
192 |
+
## Customize your own simulation
|
193 |
+
|
194 |
+
NOTE: every time you change character data, you should re-run
|
195 |
+
`just convex run testing:wipeAllTables` and then
|
196 |
+
`npm run dev` to re-upload everything to Convex.
|
197 |
+
This is because character data is sent to Convex on the initial load.
|
198 |
+
However, beware that `just convex run testing:wipeAllTables` WILL wipe all of your data.
|
199 |
+
|
200 |
+
1. Create your own characters and stories: All characters and stories, as well as their spritesheet references are stored in [characters.ts](./data/characters.ts). You can start by changing character descriptions.
|
201 |
+
|
202 |
+
2. Updating spritesheets: in `data/characters.ts`, you will see this code:
|
203 |
+
|
204 |
+
```ts
|
205 |
+
export const characters = [
|
206 |
+
{
|
207 |
+
name: 'f1',
|
208 |
+
textureUrl: '/assets/32x32folk.png',
|
209 |
+
spritesheetData: f1SpritesheetData,
|
210 |
+
speed: 0.1,
|
211 |
+
},
|
212 |
+
...
|
213 |
+
];
|
214 |
```
|
215 |
|
216 |
+
You should find a sprite sheet for your character, and define sprite motion / assets in the corresponding file (in the above example, `f1SpritesheetData` was defined in f1.ts)
|
217 |
+
|
218 |
+
3. Update the Background (Environment): The map gets loaded in `convex/init.ts` from `data/gentle.js`. To update the map, follow these steps:
|
219 |
+
|
220 |
+
- Use [Tiled](https://www.mapeditor.org/) to export tilemaps as a JSON file (2 layers named bgtiles and objmap)
|
221 |
+
- Use the `convertMap.js` script to convert the JSON to a format that the engine can use.
|
222 |
+
|
223 |
+
```console
|
224 |
+
node data/convertMap.js <mapDataPath> <assetPath> <tilesetpxw> <tilesetpxh>
|
225 |
+
```
|
226 |
+
|
227 |
+
- `<mapDataPath>`: Path to the Tiled JSON file.
|
228 |
+
- `<assetPath>`: Path to tileset images.
|
229 |
+
- `<tilesetpxw>`: Tileset width in pixels.
|
230 |
+
- `<tilesetpxh>`: Tileset height in pixels.
|
231 |
+
Generates `converted-map.js` that you can use like `gentle.js`
|
232 |
+
|
233 |
+
4. Change the background music by modifying the prompt in `convex/music.ts`
|
234 |
+
5. Change how often to generate new music at `convex/crons.ts` by modifying the `generate new background music` job
|
235 |
+
|
236 |
+
## Using a cloud AI Provider
|
237 |
+
|
238 |
+
Configure `convex/util/llm.ts` or set these env variables:
|
239 |
+
|
240 |
+
```sh
|
241 |
+
# Local Convex
|
242 |
+
just convex env set LLM_API_HOST # url
|
243 |
+
just convex env set LLM_MODEL # model
|
244 |
+
# Cloud Convex
|
245 |
+
npx convex env set LLM_API_HOST # url
|
246 |
+
npx convex env set LLM_MODEL # model
|
247 |
+
```
|
248 |
+
|
249 |
+
The embeddings model config needs to be changed [in code](./convex/util/llm.ts),
|
250 |
+
since you need to specify the embeddings dimension.
|
251 |
+
|
252 |
+
### Keys
|
253 |
+
|
254 |
+
For Together.ai, visit https://api.together.xyz/settings/api-keys
|
255 |
+
For OpenAI, visit https://platform.openai.com/account/api-keys
|
256 |
+
|
257 |
+
## Using hosted Convex
|
258 |
+
|
259 |
+
You can run your Convex backend in the cloud by just running
|
260 |
+
|
261 |
+
```sh
|
262 |
+
npx convex dev --once --configure
|
263 |
+
```
|
264 |
+
|
265 |
+
And updating the `package.json` scripts to remove `just`:
|
266 |
+
change `just convex ...` to `convex ...`.
|
267 |
+
|
268 |
+
You'll then need to set any environment variables you had locally in the cloud
|
269 |
+
environment with `npx convex env set` or on the dashboard:
|
270 |
+
https://dashboard.convex.dev/deployment/settings/environment-variables
|
271 |
+
|
272 |
+
To run commands, use `npx convex ...` where you used to run `just convex ...`.
|
273 |
+
|
274 |
+
## Deploy the app
|
275 |
+
|
276 |
+
### Deploy Convex functions to prod environment
|
277 |
+
|
278 |
+
Before you can run the app, you will need to make sure the Convex functions are deployed to its production environment.
|
279 |
+
|
280 |
+
1. Run `npx convex deploy` to deploy the convex functions to production
|
281 |
+
2. Run `npx convex run init --prod`
|
282 |
+
|
283 |
+
If you have existing data you want to clear, you can run `npx convex run testing:wipeAllTables --prod`
|
284 |
+
|
285 |
+
### Adding Auth (Optional)
|
286 |
+
|
287 |
+
You can add clerk auth back in with `git revert b44a436`.
|
288 |
+
Or just look at that diff for what changed to remove it.
|
289 |
+
|
290 |
+
**Make a Clerk account**
|
291 |
+
|
292 |
+
- Go to https://dashboard.clerk.com/ and click on "Add Application"
|
293 |
+
- Name your application and select the sign-in providers you would like to offer users
|
294 |
+
- Create Application
|
295 |
+
- Add `VITE_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` to `.env.local`
|
296 |
+
|
297 |
+
```bash
|
298 |
+
VITE_CLERK_PUBLISHABLE_KEY=pk_***
|
299 |
+
CLERK_SECRET_KEY=sk_***
|
300 |
+
```
|
301 |
+
|
302 |
+
- Go to JWT Templates and create a new Convex Template.
|
303 |
+
- Copy the JWKS endpoint URL for use below.
|
304 |
+
|
305 |
+
```sh
|
306 |
+
npx convex env set CLERK_ISSUER_URL # e.g. https://your-issuer-url.clerk.accounts.dev/
|
307 |
+
```
|
308 |
+
|
309 |
+
### Deploy to Vercel
|
310 |
+
|
311 |
+
- Register an account on Vercel and then [install the Vercel CLI](https://vercel.com/docs/cli).
|
312 |
+
- **If you are using Github Codespaces**: You will need to [install the Vercel CLI](https://vercel.com/docs/cli) and authenticate from your codespaces cli by running `vercel login`.
|
313 |
+
- Deploy the app to Vercel with `vercel --prod`.
|
314 |
+
|
315 |
+
## Using local inference from a cloud deployment.
|
316 |
+
|
317 |
+
We support using [Ollama](https://github.com/jmorganca/ollama) for conversation generations.
|
318 |
+
To have it accessible from the web, you can use Tunnelmole or Ngrok or similar.
|
319 |
+
|
320 |
+
**Using Tunnelmole**
|
321 |
+
|
322 |
+
[Tunnelmole](https://github.com/robbie-cahill/tunnelmole-client) is an open source tunneling tool.
|
323 |
+
|
324 |
+
You can install Tunnelmole using one of the following options:
|
325 |
+
|
326 |
+
- NPM: `npm install -g tunnelmole`
|
327 |
+
- Linux: `curl -s https://tunnelmole.com/sh/install-linux.sh | sudo bash`
|
328 |
+
- Mac: `curl -s https://tunnelmole.com/sh/install-mac.sh --output install-mac.sh && sudo bash install-mac.sh`
|
329 |
+
- Windows: Install with NPM, or if you don't have NodeJS installed, download the `exe` file for Windows [here](https://tunnelmole.com/downloads/tmole.exe) and put it somewhere in your PATH.
|
330 |
+
|
331 |
+
Once Tunnelmole is installed, run the following command:
|
332 |
+
|
333 |
+
```
|
334 |
+
tmole 11434
|
335 |
+
```
|
336 |
+
|
337 |
+
Tunnelmole should output a unique url once you run this command.
|
338 |
+
|
339 |
+
**Using Ngrok**
|
340 |
+
|
341 |
+
Ngrok is a popular closed source tunneling tool.
|
342 |
+
|
343 |
+
- [Install Ngrok](https://ngrok.com/docs/getting-started/)
|
344 |
+
|
345 |
+
Once ngrok is installed and authenticated, run the following command:
|
346 |
+
|
347 |
+
```
|
348 |
+
ngrok http http://localhost:11434
|
349 |
+
```
|
350 |
+
|
351 |
+
Ngrok should output a unique url once you run this command.
|
352 |
+
|
353 |
+
**Add Ollama endpoint to Convex**
|
354 |
+
|
355 |
+
```sh
|
356 |
+
npx convex env set OLLAMA_HOST # your tunnelmole/ngrok unique url from the previous step
|
357 |
+
```
|
358 |
+
|
359 |
+
**Update Ollama domains**
|
360 |
+
|
361 |
+
Ollama has a list of accepted domains. Add the ngrok domain so it won't reject
|
362 |
+
traffic. see ollama.ai for more details.
|
363 |
+
|
364 |
+
## Credits
|
365 |
+
|
366 |
+
- All interactions, background music and rendering on the <Game/> component in the project are powered by [PixiJS](https://pixijs.com/).
|
367 |
+
- Tilesheet:
|
368 |
+
- https://opengameart.org/content/16x16-game-assets by George Bailey
|
369 |
+
- https://opengameart.org/content/16x16-rpg-tileset by hilau
|
370 |
+
- We used https://github.com/pierpo/phaser3-simple-rpg for the original POC of this project. We have since re-wrote the whole app, but appreciated the easy starting point
|
371 |
+
- Original assets by [ansimuz](https://opengameart.org/content/tiny-rpg-forest)
|
372 |
+
- The UI is based on original assets by [Mounir Tohami](https://mounirtohami.itch.io/pixel-art-gui-elements)
|
373 |
+
|
374 |
+
# π§βπ« What is Convex?
|
375 |
+
|
376 |
+
[Convex](https://convex.dev) is a hosted backend platform with a
|
377 |
+
built-in database that lets you write your
|
378 |
+
[database schema](https://docs.convex.dev/database/schemas) and
|
379 |
+
[server functions](https://docs.convex.dev/functions) in
|
380 |
+
[TypeScript](https://docs.convex.dev/typescript). Server-side database
|
381 |
+
[queries](https://docs.convex.dev/functions/query-functions) automatically
|
382 |
+
[cache](https://docs.convex.dev/functions/query-functions#caching--reactivity) and
|
383 |
+
[subscribe](https://docs.convex.dev/client/react#reactivity) to data, powering a
|
384 |
+
[realtime `useQuery` hook](https://docs.convex.dev/client/react#fetching-data) in our
|
385 |
+
[React client](https://docs.convex.dev/client/react). There are also clients for
|
386 |
+
[Python](https://docs.convex.dev/client/python),
|
387 |
+
[Rust](https://docs.convex.dev/client/rust),
|
388 |
+
[ReactNative](https://docs.convex.dev/client/react-native), and
|
389 |
+
[Node](https://docs.convex.dev/client/javascript), as well as a straightforward
|
390 |
+
[HTTP API](https://docs.convex.dev/http-api/).
|
391 |
+
|
392 |
+
The database supports
|
393 |
+
[NoSQL-style documents](https://docs.convex.dev/database/document-storage) with
|
394 |
+
[opt-in schema validation](https://docs.convex.dev/database/schemas),
|
395 |
+
[relationships](https://docs.convex.dev/database/document-ids) and
|
396 |
+
[custom indexes](https://docs.convex.dev/database/indexes/)
|
397 |
+
(including on fields in nested objects).
|
398 |
+
|
399 |
+
The
|
400 |
+
[`query`](https://docs.convex.dev/functions/query-functions) and
|
401 |
+
[`mutation`](https://docs.convex.dev/functions/mutation-functions) server functions have transactional,
|
402 |
+
low latency access to the database and leverage our
|
403 |
+
[`v8` runtime](https://docs.convex.dev/functions/runtimes) with
|
404 |
+
[determinism guardrails](https://docs.convex.dev/functions/runtimes#using-randomness-and-time-in-queries-and-mutations)
|
405 |
+
to provide the strongest ACID guarantees on the market:
|
406 |
+
immediate consistency,
|
407 |
+
serializable isolation, and
|
408 |
+
automatic conflict resolution via
|
409 |
+
[optimistic multi-version concurrency control](https://docs.convex.dev/database/advanced/occ) (OCC / MVCC).
|
410 |
+
|
411 |
+
The [`action` server functions](https://docs.convex.dev/functions/actions) have
|
412 |
+
access to external APIs and enable other side-effects and non-determinism in
|
413 |
+
either our
|
414 |
+
[optimized `v8` runtime](https://docs.convex.dev/functions/runtimes) or a more
|
415 |
+
[flexible `node` runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime).
|
416 |
+
|
417 |
+
Functions can run in the background via
|
418 |
+
[scheduling](https://docs.convex.dev/scheduling/scheduled-functions) and
|
419 |
+
[cron jobs](https://docs.convex.dev/scheduling/cron-jobs).
|
420 |
+
|
421 |
+
Development is cloud-first, with
|
422 |
+
[hot reloads for server function](https://docs.convex.dev/cli#run-the-convex-dev-server) editing via the
|
423 |
+
[CLI](https://docs.convex.dev/cli),
|
424 |
+
[preview deployments](https://docs.convex.dev/production/hosting/preview-deployments),
|
425 |
+
[logging and exception reporting integrations](https://docs.convex.dev/production/integrations/),
|
426 |
+
There is a
|
427 |
+
[dashboard UI](https://docs.convex.dev/dashboard) to
|
428 |
+
[browse and edit data](https://docs.convex.dev/dashboard/deployments/data),
|
429 |
+
[edit environment variables](https://docs.convex.dev/production/environment-variables),
|
430 |
+
[view logs](https://docs.convex.dev/dashboard/deployments/logs),
|
431 |
+
[run server functions](https://docs.convex.dev/dashboard/deployments/functions), and more.
|
432 |
+
|
433 |
+
There are built-in features for
|
434 |
+
[reactive pagination](https://docs.convex.dev/database/pagination),
|
435 |
+
[file storage](https://docs.convex.dev/file-storage),
|
436 |
+
[reactive text search](https://docs.convex.dev/text-search),
|
437 |
+
[vector search](https://docs.convex.dev/vector-search),
|
438 |
+
[https endpoints](https://docs.convex.dev/functions/http-actions) (for webhooks),
|
439 |
+
[snapshot import/export](https://docs.convex.dev/database/import-export/),
|
440 |
+
[streaming import/export](https://docs.convex.dev/production/integrations/streaming-import-export), and
|
441 |
+
[runtime validation](https://docs.convex.dev/database/schemas#validators) for
|
442 |
+
[function arguments](https://docs.convex.dev/functions/args-validation) and
|
443 |
+
[database data](https://docs.convex.dev/database/schemas#schema-validation).
|
444 |
|
445 |
+
Everything scales automatically, and itβs [free to start](https://www.convex.dev/plans).
|
|
README.md.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1 |
-
title: AI Town on HuggingFace
|
2 |
-
emoji: π π»ππ€
|
3 |
-
colorFrom: green
|
4 |
-
colorTo: red
|
5 |
-
sdk: docker
|
6 |
-
app_port: 5173
|
7 |
-
pinned: false
|
8 |
-
disable_embedding: true
|
9 |
-
# header: mini
|
10 |
-
short_description: AI Town on HuggingFace
|
11 |
-
hf_oauth: true
|
12 |
-
# optional, default duration is 8 hours/480 minutes. Max duration is 30 days/43200 minutes.
|
13 |
-
hf_oauth_expiration_minutes: 480
|
14 |
-
# optional, see "Scopes" below. "openid profile" is always included.
|
15 |
-
hf_oauth_scopes:
|
16 |
-
- read-repos
|
17 |
-
- manage-repos
|
18 |
-
- inference-api
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{patches/assets β assets}/32x32folk.png
RENAMED
File without changes
|
{patches/assets β assets}/GrayCat.png
RENAMED
File without changes
|
{patches/assets β assets}/OrangeCat.png
RENAMED
File without changes
|
{patches/assets β assets}/a16z.png
RENAMED
File without changes
|
{patches/assets β assets}/background.webp
RENAMED
File without changes
|
{patches/assets β assets}/close.svg
RENAMED
File without changes
|
{patches/assets β assets}/cloud.jpg
RENAMED
File without changes
|
{patches/assets β assets}/convex-bg.webp
RENAMED
File without changes
|
{patches/assets β assets}/convex.svg
RENAMED
File without changes
|
{patches/assets β assets}/favicon.ico
RENAMED
File without changes
|
{patches/assets β assets}/fonts/upheaval_pro.ttf
RENAMED
File without changes
|
{patches/assets β assets}/fonts/vcr_osd_mono.ttf
RENAMED
File without changes
|
{patches/assets β assets}/heart-empty.png
RENAMED
File without changes
|
{patches/assets β assets}/help.svg
RENAMED
File without changes
|
{patches/assets β assets}/hf.svg
RENAMED
File without changes
|
{patches/assets β assets}/interact.svg
RENAMED
File without changes
|
{patches/assets β assets}/magecity.png
RENAMED
File without changes
|
map.png β assets/map.png
RENAMED
File without changes
|
{patches/assets β assets}/map_night.png
RENAMED
File without changes
|
{patches/assets β assets}/player.png
RENAMED
File without changes
|
{patches/assets β assets}/rpg-tileset.png
RENAMED
File without changes
|
{patches/assets β assets}/spritesheets/campfire.png
RENAMED
File without changes
|
{patches/assets β assets}/spritesheets/gentlesparkle32.png
RENAMED
File without changes
|
{patches/assets β assets}/spritesheets/gentlewaterfall32.png
RENAMED
File without changes
|
{patches/assets β assets}/spritesheets/windmill.png
RENAMED
File without changes
|
{patches/assets β assets}/star.svg
RENAMED
File without changes
|
{patches/assets β assets}/tilemap.json
RENAMED
File without changes
|
{patches/assets β assets}/ui/box.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/bubble-left.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/bubble-right.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/button.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/button_pressed.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/chats.svg
RENAMED
File without changes
|
{patches/assets β assets}/ui/desc.svg
RENAMED
File without changes
|