diff --git a/package-lock.json b/package-lock.json index fbea47eeff49467b5268a5adf08dc6d96afefc84..7a113eec1d4f364d3a18fa69120735ecfd521671 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tooltip": "^1.0.6", "@silevis/reactgrid": "^4.0.5", "@tanstack/react-query": "^4.30.0", "@tanstack/react-table": "^8.9.3", @@ -55,6 +56,8 @@ "react": "18.2.0", "react-circular-progressbar": "^2.1.0", "react-day-picker": "^8.8.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "18.2.0", "react-photo-sphere-viewer": "^3.3.5-psv5.1.4", "tailwind-merge": "^1.13.2", @@ -1433,6 +1436,40 @@ } } }, + "node_modules/@radix-ui/react-tooltip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.6.tgz", + "integrity": "sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-dismissable-layer": "1.0.4", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-popper": "1.1.2", + "@radix-ui/react-portal": "1.0.3", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-slot": "1.0.2", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-visually-hidden": "1.0.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz", @@ -1587,6 +1624,21 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@react-dnd/asap": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-5.0.2.tgz", + "integrity": "sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==" + }, + "node_modules/@react-dnd/invariant": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-4.0.2.tgz", + "integrity": "sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==" + }, + "node_modules/@react-dnd/shallowequal": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz", + "integrity": "sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==" + }, "node_modules/@rushstack/eslint-patch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.3.2.tgz", @@ -2856,6 +2908,16 @@ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" }, + "node_modules/dnd-core": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-16.0.1.tgz", + "integrity": "sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==", + "dependencies": { + "@react-dnd/asap": "^5.0.1", + "@react-dnd/invariant": "^4.0.1", + "redux": "^4.2.0" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -3887,6 +3949,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -5128,6 +5198,43 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-dnd": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-16.0.1.tgz", + "integrity": "sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==", + "dependencies": { + "@react-dnd/invariant": "^4.0.1", + "@react-dnd/shallowequal": "^4.0.1", + "dnd-core": "^16.0.1", + "fast-deep-equal": "^3.1.3", + "hoist-non-react-statics": "^3.3.2" + }, + "peerDependencies": { + "@types/hoist-non-react-statics": ">= 3.3.1", + "@types/node": ">= 12", + "@types/react": ">= 16", + "react": ">= 16.14" + }, + "peerDependenciesMeta": { + "@types/hoist-non-react-statics": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-dnd-html5-backend": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz", + "integrity": "sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==", + "dependencies": { + "dnd-core": "^16.0.1" + } + }, "node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -5263,6 +5370,14 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", diff --git a/package.json b/package.json index 565a5827ee077fe3fd86d3a1585b8c0cbfe73a06..3c8cd79128ad951e620001d407409a86f334b4a8 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tooltip": "^1.0.6", "@silevis/reactgrid": "^4.0.5", "@tanstack/react-query": "^4.30.0", "@tanstack/react-table": "^8.9.3", @@ -56,6 +57,8 @@ "react": "18.2.0", "react-circular-progressbar": "^2.1.0", "react-day-picker": "^8.8.0", + "react-dnd": "^16.0.1", + "react-dnd-html5-backend": "^16.0.1", "react-dom": "18.2.0", "react-photo-sphere-viewer": "^3.3.5-psv5.1.4", "tailwind-merge": "^1.13.2", diff --git a/public/inventories/arizona/matchbox.jpeg b/public/inventories/arizona/matchbox.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..06b029cd9026d4dcfb73b8afebeda9e106c2bae3 Binary files /dev/null and b/public/inventories/arizona/matchbox.jpeg differ diff --git a/public/inventories/arizona/pickaxe.jpeg b/public/inventories/arizona/pickaxe.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9e49fc4c8e99595e9fa0de8c8df5acb17649d4df Binary files /dev/null and b/public/inventories/arizona/pickaxe.jpeg differ diff --git a/public/inventories/doom/box.jpeg b/public/inventories/doom/box.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..21aaf5e31ef43c52b8785d6a1ea17beb1d84e0cb Binary files /dev/null and b/public/inventories/doom/box.jpeg differ diff --git a/public/inventories/doom/first-aid.jpeg b/public/inventories/doom/first-aid.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a084f142da87d4504734da6df25c3ec51f9621e1 Binary files /dev/null and b/public/inventories/doom/first-aid.jpeg differ diff --git a/public/inventories/doom/laser-gun.jpeg b/public/inventories/doom/laser-gun.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..197353a65454514e87c6399a3e7fd59c0cd7a88e Binary files /dev/null and b/public/inventories/doom/laser-gun.jpeg differ diff --git a/public/inventories/dungeon/axe.jpeg b/public/inventories/dungeon/axe.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..277aec447ec332e5b6740c21b2e3b34c90ab4ced Binary files /dev/null and b/public/inventories/dungeon/axe.jpeg differ diff --git a/public/inventories/dungeon/box.jpeg b/public/inventories/dungeon/box.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..aba60d626b428e4684990192666b8100d18ff8ed Binary files /dev/null and b/public/inventories/dungeon/box.jpeg differ diff --git a/public/inventories/dungeon/candlestick.jpeg b/public/inventories/dungeon/candlestick.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..3f72d131bf9beba3deefeb74ec6c8148b9d05d98 Binary files /dev/null and b/public/inventories/dungeon/candlestick.jpeg differ diff --git a/public/inventories/dungeon/rabbit-foot.jpeg b/public/inventories/dungeon/rabbit-foot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..021e175f5ea3c983a794aae6729da1bf3e97c638 Binary files /dev/null and b/public/inventories/dungeon/rabbit-foot.jpeg differ diff --git a/public/inventories/dungeon/skull.jpeg b/public/inventories/dungeon/skull.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0f435f510aa02864e60abe1a4cad6a4b4ffcb928 Binary files /dev/null and b/public/inventories/dungeon/skull.jpeg differ diff --git a/public/inventories/enchanters/garden-gnome.jpeg b/public/inventories/enchanters/garden-gnome.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8eee11ac4ef9d721ac0d4d1eacb941a338bab3a4 Binary files /dev/null and b/public/inventories/enchanters/garden-gnome.jpeg differ diff --git a/public/inventories/enchanters/key.jpeg b/public/inventories/enchanters/key.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b044d1bdc92e906f3c73d0a8959f41eea65baec8 Binary files /dev/null and b/public/inventories/enchanters/key.jpeg differ diff --git a/public/inventories/enchanters/old-book.jpeg b/public/inventories/enchanters/old-book.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..1b0464a757b94e1ee03a3dceae4b1d8d130ad0b0 Binary files /dev/null and b/public/inventories/enchanters/old-book.jpeg differ diff --git a/public/inventories/enchanters/pixie-dust.jpeg b/public/inventories/enchanters/pixie-dust.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..adffc4efe3e9f7dd8631f2ad550d764ba1247dbd Binary files /dev/null and b/public/inventories/enchanters/pixie-dust.jpeg differ diff --git a/public/inventories/flamenco/alien-crab.jpeg b/public/inventories/flamenco/alien-crab.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d9dcb162c2a40164c128fc4205c5b4a930d8a0c8 Binary files /dev/null and b/public/inventories/flamenco/alien-crab.jpeg differ diff --git a/public/inventories/flamenco/burger.jpeg b/public/inventories/flamenco/burger.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b5293643a5f00b6528f6346f20388a298c1687a9 Binary files /dev/null and b/public/inventories/flamenco/burger.jpeg differ diff --git a/public/inventories/flamenco/chicken.jpeg b/public/inventories/flamenco/chicken.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..82145ca3ede3658c92495f6a454be7f245e263a3 Binary files /dev/null and b/public/inventories/flamenco/chicken.jpeg differ diff --git a/public/inventories/flamenco/fishbone.jpeg b/public/inventories/flamenco/fishbone.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d509c69f8359acf2dbc62361645f796722b94cc8 Binary files /dev/null and b/public/inventories/flamenco/fishbone.jpeg differ diff --git a/public/inventories/flamenco/skunk.jpeg b/public/inventories/flamenco/skunk.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a5c12c51ad80c1cfdb827619c20a0affbf88af48 Binary files /dev/null and b/public/inventories/flamenco/skunk.jpeg differ diff --git a/public/inventories/flamenco/tentacle.jpeg b/public/inventories/flamenco/tentacle.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..85eedc1a27bcef38d89fca4c0539b45481fb2e33 Binary files /dev/null and b/public/inventories/flamenco/tentacle.jpeg differ diff --git a/public/inventories/nexus/box.jpeg b/public/inventories/nexus/box.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..a5f33ce8192a8f03bf2a554ba8113b2d6ae0223f Binary files /dev/null and b/public/inventories/nexus/box.jpeg differ diff --git a/public/inventories/nexus/disk.jpeg b/public/inventories/nexus/disk.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f78b30baaada3fc5372d380be6c26e01cba50eee Binary files /dev/null and b/public/inventories/nexus/disk.jpeg differ diff --git a/public/inventories/nexus/eyeball.jpeg b/public/inventories/nexus/eyeball.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c482392dd2d01c485b61105acb09af5f2e955d9c Binary files /dev/null and b/public/inventories/nexus/eyeball.jpeg differ diff --git a/public/inventories/nexus/parasite.jpeg b/public/inventories/nexus/parasite.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0112cb2371f88b13b63d0ad1e818fb736013991e Binary files /dev/null and b/public/inventories/nexus/parasite.jpeg differ diff --git a/public/inventories/nexus/robot-arm.jpeg b/public/inventories/nexus/robot-arm.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..df51b685354b0af047bbafd39cba4a269e6e55a2 Binary files /dev/null and b/public/inventories/nexus/robot-arm.jpeg differ diff --git a/public/inventories/nexus/robot-hand.jpeg b/public/inventories/nexus/robot-hand.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d11c961758bcce94331df345eaf0109bbcbd401c Binary files /dev/null and b/public/inventories/nexus/robot-hand.jpeg differ diff --git a/public/inventories/pharaoh/bowl.jpeg b/public/inventories/pharaoh/bowl.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4521f19afc7101608f038d3ba6e83ff234e5d521 Binary files /dev/null and b/public/inventories/pharaoh/bowl.jpeg differ diff --git a/public/inventories/pharaoh/box.jpeg b/public/inventories/pharaoh/box.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c1415fd82a435813fbb2f071a801be8bed13692f Binary files /dev/null and b/public/inventories/pharaoh/box.jpeg differ diff --git a/public/inventories/pharaoh/golden-beetle.jpeg b/public/inventories/pharaoh/golden-beetle.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..02a53164aaff48ae944d156392f12638e2c07151 Binary files /dev/null and b/public/inventories/pharaoh/golden-beetle.jpeg differ diff --git a/public/inventories/pharaoh/plastic-sphinx.jpeg b/public/inventories/pharaoh/plastic-sphinx.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..b9200b9e2928e1e58bfc45769e5c65d9388086b1 Binary files /dev/null and b/public/inventories/pharaoh/plastic-sphinx.jpeg differ diff --git a/public/inventories/pharaoh/staff.jpeg b/public/inventories/pharaoh/staff.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..01266e46b74983b8ca231ebfe51ece1d4559a481 Binary files /dev/null and b/public/inventories/pharaoh/staff.jpeg differ diff --git a/public/inventories/pirates/coconut.jpeg b/public/inventories/pirates/coconut.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d06c13ab037eb8fad1849033b48bd3d20d2c7f40 Binary files /dev/null and b/public/inventories/pirates/coconut.jpeg differ diff --git a/public/inventories/pirates/compass.jpeg b/public/inventories/pirates/compass.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0420c54ce710c70932d1453087caaadfc67f6a4e Binary files /dev/null and b/public/inventories/pirates/compass.jpeg differ diff --git a/public/inventories/pirates/crystal-skull.jpeg b/public/inventories/pirates/crystal-skull.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..eab7a490f946e6071f806e4dc8bf8d0164d08f49 Binary files /dev/null and b/public/inventories/pirates/crystal-skull.jpeg differ diff --git a/public/inventories/pirates/fishbone.jpeg b/public/inventories/pirates/fishbone.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f965938e707eab51d63067b66aff76662a140b90 Binary files /dev/null and b/public/inventories/pirates/fishbone.jpeg differ diff --git a/public/inventories/pirates/lizard.jpeg b/public/inventories/pirates/lizard.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..29d9af14f8a64108d85a8425f048a4899a06bd54 Binary files /dev/null and b/public/inventories/pirates/lizard.jpeg differ diff --git a/public/inventories/pirates/parrot.jpeg b/public/inventories/pirates/parrot.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..da5170104ba74e14179bc73a63a615065e10fd97 Binary files /dev/null and b/public/inventories/pirates/parrot.jpeg differ diff --git a/public/inventories/pirates/pirate-hat.jpeg b/public/inventories/pirates/pirate-hat.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7f98ec4258322f0050c6e532930e03d487fbd9a2 Binary files /dev/null and b/public/inventories/pirates/pirate-hat.jpeg differ diff --git a/public/inventories/pirates/skunk.jpeg b/public/inventories/pirates/skunk.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..453ecfe07b00af47db19bd856a313ef8ebccfae9 Binary files /dev/null and b/public/inventories/pirates/skunk.jpeg differ diff --git a/public/inventories/tensor/blue-pill.jpeg b/public/inventories/tensor/blue-pill.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8a63e6581cec421fd83bd6903d3e8c26cc7abd09 Binary files /dev/null and b/public/inventories/tensor/blue-pill.jpeg differ diff --git a/public/inventories/tensor/flash-light.jpeg b/public/inventories/tensor/flash-light.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..249e0dee0907ba802fe7ec921cd3b15c89136070 Binary files /dev/null and b/public/inventories/tensor/flash-light.jpeg differ diff --git a/public/inventories/tensor/laptop.jpeg b/public/inventories/tensor/laptop.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7aa180de35015b900fcda384847d515898a868b8 Binary files /dev/null and b/public/inventories/tensor/laptop.jpeg differ diff --git a/public/inventories/tensor/matchbox.jpeg b/public/inventories/tensor/matchbox.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c1333065abd5fa21e8f54fe4801274c7eb78e53e Binary files /dev/null and b/public/inventories/tensor/matchbox.jpeg differ diff --git a/public/inventories/tensor/watch.jpeg b/public/inventories/tensor/watch.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c449e8a0dd703b24ad062226b477ee2ef6865ddf Binary files /dev/null and b/public/inventories/tensor/watch.jpeg differ diff --git a/public/inventories/vernian/apparatus.jpeg b/public/inventories/vernian/apparatus.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f4b9abb6d3e207398fd3e46f8f9a687c45d622a7 Binary files /dev/null and b/public/inventories/vernian/apparatus.jpeg differ diff --git a/public/inventories/vernian/book.jpeg b/public/inventories/vernian/book.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e610a319bd094f67098a3e1cd885122efc634c41 Binary files /dev/null and b/public/inventories/vernian/book.jpeg differ diff --git a/public/inventories/vernian/box.jpeg b/public/inventories/vernian/box.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..13ac4fbcbd14535c8c19f95f1915ca5a05af95bf Binary files /dev/null and b/public/inventories/vernian/box.jpeg differ diff --git a/public/inventories/vernian/cog.jpeg b/public/inventories/vernian/cog.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..ea1b684a08450ff9a39ab9ea688a4ddd063e861f Binary files /dev/null and b/public/inventories/vernian/cog.jpeg differ diff --git a/public/inventories/vernian/coil.jpeg b/public/inventories/vernian/coil.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..abb651707d7152777220aad4a61bcece70460a38 Binary files /dev/null and b/public/inventories/vernian/coil.jpeg differ diff --git a/public/inventories/vernian/copper-wire.jpeg b/public/inventories/vernian/copper-wire.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..78dfe70c722e73a54c84f04837d4009851703350 Binary files /dev/null and b/public/inventories/vernian/copper-wire.jpeg differ diff --git a/public/inventories/vernian/pocket-watch.jpeg b/public/inventories/vernian/pocket-watch.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..6027e838b695099eddf2cc36769280c9e01d1fce Binary files /dev/null and b/public/inventories/vernian/pocket-watch.jpeg differ diff --git a/public/inventories/vernian/top-hat.jpeg b/public/inventories/vernian/top-hat.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..89a15e199f00d61b02bfad5a5f28eb472027b78e Binary files /dev/null and b/public/inventories/vernian/top-hat.jpeg differ diff --git a/src/app/games/arizona.ts b/src/app/games/arizona.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed7c4fb7f32726b3bd96255fdf14efabed9ddf1f --- /dev/null +++ b/src/app/games/arizona.ts @@ -0,0 +1,58 @@ +import { imfell } from "@/lib/fonts" +import { Game } from "./types" +import { InventoryItem } from "../types" + +const initialSituation = [ + `looking at an abandonned mining town street`, + `street level view`, + `looking at wooden buildings, sheriff sign, horses`, + `cactus` +].join(", ") + +const initialActionnables = [ + "horse", + "sign", + "bucket", + "ground", + "rope", + "door", + "sun", + "window", + "cactus", + "sky" +] + +const inventory: InventoryItem[] = [ + { + name: "pickaxe", + title: "Pickaxe", + caption: "", + description: "A mining pickaxe. For like, mining ore or something." + }, + { + name: "matchbox", + title: "Matchbox", + caption: "", + description: "A box of matches, to put some fire in your life." + } +] + +export const game: Game = { + title: "Arizona", + type: "arizona", + engine: "spherical_image", + className: imfell.className, + initialSituation, + initialActionnables, + inventory, + getScenePrompt: (situation?: string) => [ + `Screenshot from a videogame`, + `unreal engine`, + `old mining town`, + `in arizona`, + `wild west america`, + `during gold rush era`, + situation || initialSituation, + ] +} + diff --git a/src/app/games/city.ts b/src/app/games/city.ts index 7192df56466146756994939a42c8c3d5279d9648..6fd50bd2943744496730666964cefd1be9acc7ee 100644 --- a/src/app/games/city.ts +++ b/src/app/games/city.ts @@ -1,5 +1,6 @@ import { edu } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const actions = [ "busy pedestrians", @@ -43,6 +44,15 @@ const initialActionnables = [ "roof" ] +const inventory: InventoryItem[] = [ + // { + // name: "pickaxe", + // title: "Pickaxe", + // caption: "", + // description: "" + // }, +] + export const game: Game = { title: "City", type: "city", @@ -50,6 +60,7 @@ export const game: Game = { className: edu.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `isometrical bird view of 3D rendered city`, `game screenshot`, diff --git a/src/app/games/doom.ts b/src/app/games/doom.ts index 57dd72e6cb751bb84d2971aebf66f926905fa134..d4c08a37458106e575c0fa58363bfb4107f9a9b3 100644 --- a/src/app/games/doom.ts +++ b/src/app/games/doom.ts @@ -1,5 +1,6 @@ import { orbitron } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `looking at building on Mars, with multiple moons in the sky`, @@ -18,6 +19,27 @@ const initialActionnables = [ "rocks" ] +const inventory: InventoryItem[] = [ + { + name: "box", + title: "Box", + caption: "", + description: "A strange metal box." + }, + { + name: "first-aid", + title: "First-aid kit", + caption: "", + description: "Might come in handy!" + }, + { + name: "laser-gun", + title: "Laser gun", + caption: "", + description: "Bzing bzing!" + }, +] + export const game: Game = { title: "Doom", type: "doom", @@ -25,6 +47,7 @@ export const game: Game = { className: orbitron.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `Screenshot from Doom`, `first person`, diff --git a/src/app/games/dungeon.ts b/src/app/games/dungeon.ts index 3469a0ea9f0721417b29aabaf130ec34fae42bdf..e36de5e986afb622f43f92d09d636895971f34bd 100644 --- a/src/app/games/dungeon.ts +++ b/src/app/games/dungeon.ts @@ -1,5 +1,6 @@ import { amatic } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const actions = [ "not moving", @@ -46,6 +47,39 @@ const initialActionnables = [ "fireplace" ] +const inventory: InventoryItem[] = [ + { + name: "axe", + title: "Axe", + caption: "", + description: "A good dwarf is nothing without its axe!" + }, + { + name: "box", + title: "Box", + caption: "", + description: "Hmm, a mysterious box.." + }, + { + name: "candlestick", + title: "Candlestick", + caption: "", + description: "This candlestick looks strange.." + }, + { + name: "rabbit-foot", + title: "Rabbit foot", + caption: "", + description: "I hope it will bring me luck!" + }, + { + name: "skull", + title: "Skull", + caption: "", + description: "The skull of some poor fellow." + }, +] + export const game: Game = { title: "Dungeon", type: "dungeon", @@ -53,6 +87,7 @@ export const game: Game = { className: amatic.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `screenshot from adventure videogame`, // `first-person footage`, diff --git a/src/app/games/enchanters.ts b/src/app/games/enchanters.ts index 1dd43f3b75f0d450b101532dab639915edd020b9..9a2b1622374dc474435d491ee07ed8a53817b83a 100644 --- a/src/app/games/enchanters.ts +++ b/src/app/games/enchanters.ts @@ -1,5 +1,6 @@ import { macondo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `looking at a beautiful medieval castle on a lake, with a metallic gate, during golden hour, surrounded by mountain, with a flying dragon visible afar`, @@ -18,6 +19,33 @@ const initialActionnables = [ "sky" ] +const inventory: InventoryItem[] = [ + { + name: "garden-gnome", + title: "Garden gnome", + caption: "", + description: "Found in a mystical garden." + }, + { + name: "key", + title: "Key", + caption: "", + description: "Ha-ah! I wonder what it opens?" + }, + { + name: "old-book", + title: "Old book", + caption: "", + description: "Written in an ancient elfic language" + }, + { + name: "pixie-dust", + title: "Pixie dust", + caption: "", + description: "Well, it is magical for sure." + }, +] + export const game: Game = { title: "Enchanters", type: "enchanters", @@ -25,6 +53,7 @@ export const game: Game = { className: macondo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `Screenshot from a videogame`, `unreal engine`, diff --git a/src/app/games/flamenco.ts b/src/app/games/flamenco.ts index c2e02546a0623bde16a879a89fe16a0e341a5e05..fb55a68afc56e65bcfe204f6e539c62267f3fe59 100644 --- a/src/app/games/flamenco.ts +++ b/src/app/games/flamenco.ts @@ -1,5 +1,6 @@ import { macondo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `beautiful view of an art deco building in new york`, @@ -23,6 +24,33 @@ const initialActionnables = [ "door" ] +const inventory: InventoryItem[] = [ + { + name: "burger", + title: "Burger", + caption: "", + description: "I forgot to eat it." + }, + { + name: "chicken", + title: "Chicken", + caption: "", + description: "Well it does eggs, so yes it is useful!" + }, + { + name: "fishbone", + title: "Fishbone", + caption: "", + description: "Maybe I could pick some locks with it?" + }, + { + name: "tentacle", + title: "Tentacle", + caption: "", + description: "I found this strange tentacle.. this is evidence!" + }, +] + export const game: Game = { title: "Sad Flamenco", type: "flamenco", @@ -30,6 +58,7 @@ export const game: Game = { className: macondo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `photo of an artdeco scene`, `grimfandango screenshot`, diff --git a/src/app/games/index.ts b/src/app/games/index.ts index 498c55d29de24137c95b62a63bb82cbac06f1197..9533140c4279bdbe51845ac52355648b9ec2f8d4 100644 --- a/src/app/games/index.ts +++ b/src/app/games/index.ts @@ -10,8 +10,9 @@ import { game as flamenco } from "./flamenco" import { game as pharaoh } from "./pharaoh" import { game as tensor } from "./tensor" import { game as nexus } from "./nexus" +import { game as arizona } from "./arizona" -export const games = { pirates, city, dungeon, doom, vernian, enchanters, flamenco, pharaoh, tensor, nexus} +export const games = { arizona, pirates, city, dungeon, doom, vernian, enchanters, flamenco, pharaoh, tensor, nexus} export const defaultGame: GameType = "dungeon" diff --git a/src/app/games/nexus.ts b/src/app/games/nexus.ts index fe47f74346913e97d37be7d7fb81c5c1de845860..6491e12ee1f50e4f8047fe2ff535f3cc0c938bd9 100644 --- a/src/app/games/nexus.ts +++ b/src/app/games/nexus.ts @@ -1,5 +1,6 @@ import { macondo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `first-person view of a futuristic street`, @@ -21,6 +22,47 @@ const initialActionnables = [ "door" ] +const inventory: InventoryItem[] = [ + { + name: "box", + title: "Box", + caption: "", + description: "I wonder what this box contains?" + }, + { + name: "disk", + title: "Disk", + caption: "", + description: "Now I need to find a computer.." + }, + { + name: "eyeball", + title: "Eyeball", + caption: "", + description: "Looks like it belonged to a cyborg." + }, + { + name: "parasite", + title: "Parasite", + caption: "", + description: "Don't eat this!" + }, + /* + { + name: "robot-arm", + title: "Robot arm", + caption: "", + description: "" + }, + */ + { + name: "robot-hand", + title: "Robot hand", + caption: "", + description: "" + }, +] + export const game: Game = { title: "Nexus", type: "nexus", @@ -28,6 +70,7 @@ export const game: Game = { className: macondo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `high-res photo from Blade Runner`, `cyberpunk, tokyo, futuristic clothes`, diff --git a/src/app/games/pharaoh.ts b/src/app/games/pharaoh.ts index 5961e14278c510bf75c765a2ce146ee9b3c42ab4..5a029444692d5ef20c40a7e0b52fdaa3c11c1099 100644 --- a/src/app/games/pharaoh.ts +++ b/src/app/games/pharaoh.ts @@ -1,5 +1,6 @@ import { macondo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `looking at a beautiful pyramid, ancient egypt, during golden hour, surrounded by sand dunes, near the Nile`, @@ -17,6 +18,33 @@ const initialActionnables = [ "sun" ] +const inventory: InventoryItem[] = [ + { + name: "bowl", + title: "Bowl", + caption: "", + description: "A bowl. To eat things." + }, + { + name: "box", + title: "Box", + caption: "", + description: "Full of mysteries." + }, + { + name: "golden-beetle", + title: "Beetle pendant", + caption: "", + description: "This pendant has a mysterious aura.." + }, + { + name: "staff", + title: "Staff", + caption: "", + description: "This used to belong to a magician." + }, +] + export const game: Game = { title: "Pharaoh", type: "pharaoh", @@ -24,6 +52,7 @@ export const game: Game = { className: macondo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `Screenshot from a videogame`, `unreal engine`, diff --git a/src/app/games/pirates.ts b/src/app/games/pirates.ts index 581af9cb0e5d316904aa9bbc5c57df2765a8246e..a904d2c688c09f8735c8355af059c127e123b6ab 100644 --- a/src/app/games/pirates.ts +++ b/src/app/games/pirates.ts @@ -1,5 +1,6 @@ import { lugrasimo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const actions = [ "idling", @@ -25,6 +26,57 @@ const lights = [ "during the day", ] +const inventory: InventoryItem[] = [ + { + name: "coconut", + title: "Coconut", + caption: "", + description: "Might be useful for lunch or fighting." + }, + { + name: "compass", + title: "Compass", + caption: "", + description: "Never get lost in the Seven Seas!" + }, + { + name: "crystal-skull", + title: "Crystall skull", + caption: "", + description: "It says \"Made in Germany\"." + }, + { + name: "fishbone", + title: "Fish bone", + caption: "", + description: "I use this to pick my teeth. And locks." + }, + { + name: "lizard", + title: "Lizard", + caption: "", + description: "Found this lizard, I call it Lizzie." + }, + { + name: "parrot", + title: "Parrot", + caption: "", + description: "Arr!" + }, + { + name: "pirate-hat", + title: "Pirate hat", + caption: "", + description: "Can't find the owner.. Now it\'s mine!" + }, + { + name: "skunk", + title: "Skunk", + caption: "", + description: "So this is where the smell was coming from!" + }, +] + const initialActionnables = [ "door", "box", @@ -66,6 +118,7 @@ export const game: Game = { className: lugrasimo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ // this prompt is beautiful: // screenshot from an adventure videogame, inside the hold of a pirate ship, with a pirate chest in the center, at sunset, beautiful, award winning, unreal engine, intricate details diff --git a/src/app/games/tensor.ts b/src/app/games/tensor.ts index cf24f7593d7000d1842d9a4433cb8e84454a66d0..8a00cda260e7b2db394020584940668fdbae87f4 100644 --- a/src/app/games/tensor.ts +++ b/src/app/games/tensor.ts @@ -1,5 +1,6 @@ import { macondo } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `in Martin Place, Sydney`, @@ -21,6 +22,39 @@ const initialActionnables = [ "door" ] +const inventory: InventoryItem[] = [ + { + name: "blue-pill", + title: "blue pill", + caption: "", + description: "My therapist said I had to eat one every day." + }, + { + name: "flash-light", + title: "Flashlight", + caption: "", + description: "In case I need to go to the bathroom during the night." + }, + { + name: "laptop", + title: "Laptop", + caption: "", + description: "My work laptop, with work stuff on it." + }, + { + name: "matchbox", + title: "Matchbox", + caption: "", + description: "I used this to light fireworks." + }, + { + name: "watch", + title: "Watch", + caption: "", + description: "Belonged to my grandpa, but I think it's a fake." + }, +] + export const game: Game = { title: "The Tensor", type: "tensor", @@ -28,6 +62,7 @@ export const game: Game = { className: macondo.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `first person photo`, `cold design, modern architecture, business district, impersonal`, diff --git a/src/app/games/types.ts b/src/app/games/types.ts index 668c73c2670cac45e7269221737b820f7c11e5c7..186d89a8450d99568ef538c490275d30166a81de 100644 --- a/src/app/games/types.ts +++ b/src/app/games/types.ts @@ -1,4 +1,5 @@ import { EngineType } from "../engines" +import { InventoryItem } from "../types" export type GameType = | "pirates" @@ -11,6 +12,7 @@ export type GameType = | "flamenco" | "tensor" | "nexus" + | "arizona" export interface Scene { actionnables: string[] @@ -24,5 +26,6 @@ export interface Game { className: string initialSituation: string initialActionnables: string[] + inventory: InventoryItem[] getScenePrompt: (situation?: string) => string[] } diff --git a/src/app/games/vernian.ts b/src/app/games/vernian.ts index d8efb057798f0fcd4d11ef8c947f151635ba02fc..84879e24a98ac8648f17915a773b0b4c5e118037 100644 --- a/src/app/games/vernian.ts +++ b/src/app/games/vernian.ts @@ -1,5 +1,6 @@ import { imfell } from "@/lib/fonts" import { Game } from "./types" +import { InventoryItem } from "../types" const initialSituation = [ `inside a secret workshop inspired by Jules Verne`, @@ -19,6 +20,51 @@ const initialActionnables = [ "ground" ] +const inventory: InventoryItem[] = [ + { + name: "apparatus", + title: "Apparatus", + caption: "", + description: "What is this strange device?" + }, + { + name: "book", + title: "Book", + caption: "", + description: "It is talking about a mysterious island, I think.." + }, + { + name: "cog", + title: "Cog", + caption: "", + description: "From some kind of mysterious machine." + }, + { + name: "coil", + title: "Coil", + caption: "", + description: "Nice, but where does it fit?" + }, + { + name: "copper-wire", + title: "Copper wire", + caption: "", + description: "Mmh, copper. I wonder how I could use that." + }, + { + name: "pocket-watch", + title: "Pocket watch", + caption: "", + description: "My my.. time passes quickly." + }, + { + name: "top-hat", + title: "Top Hat", + caption: "", + description: "For a gentleman or magician. The craft is exquisite." + }, +] + export const game: Game = { title: "Vernian", type: "vernian", @@ -26,6 +72,7 @@ export const game: Game = { className: imfell.className, initialSituation, initialActionnables, + inventory, getScenePrompt: (situation?: string) => [ `Screenshot from a videogame`, `steam punk decor`, diff --git a/src/app/main.tsx b/src/app/main.tsx index e883c5f3e9fc000ebc8cf06107ffe5424e5ca54f..c24f6333a199fc502e9f852900c623e28f85b15a 100644 --- a/src/app/main.tsx +++ b/src/app/main.tsx @@ -1,10 +1,10 @@ "use client" -import { useEffect, useRef, useState, useTransition } from "react" +import { ReactNode, useEffect, useRef, useState, useTransition } from "react" import { usePathname, useRouter, useSearchParams } from "next/navigation" -import { Renderer } from "@/components/business/renderer" +import { SceneRenderer } from "@/components/renderer" import { Select, @@ -17,7 +17,7 @@ import { Switch } from "@/components/ui/switch" import { Label } from "@/components/ui/label" import { newRender, getRender } from "./render" -import { RenderedScene } from "./types" +import { InventoryEvent, InventoryItem, RenderedScene, SceneEvent } from "./types" import { Game, GameType } from "./games/types" import { defaultGame, games, getGame } from "./games" import { getBackground } from "@/app/queries/getBackground" @@ -25,6 +25,7 @@ import { getDialogue } from "@/app/queries/getDialogue" import { getActionnables } from "@/app/queries/getActionnables" import { Engine, EngineType, defaultEngine, engines, getEngine } from "./engines" import { normalizeActionnables } from "@/lib/normalizeActionnables" +import { Inventory } from "@/components/inventory" const getInitialRenderedScene = (): RenderedScene => ({ renderId: "", @@ -55,13 +56,15 @@ export default function Main() { const [situation, setSituation] = useState("") const [dialogue, setDialogue] = useState("") - const [hoveredActionnable, setHoveredActionnable] = useState("") const [isBusy, setBusy] = useState(true) const busyRef = useRef(true) const loopRef = useRef(null) + const [lastEventString, setLastEventString] = useState("") + const [lastEvent, setLastEvent] = useState(null) + const loadNextScene = async (nextSituation?: string, nextActionnables?: string[]) => { await startTransition(async () => { @@ -157,8 +160,8 @@ export default function Main() { checkRenderedLoop() }, []) - const handleUserAction = async (actionnable: string) => { - console.log("user clicked on:", actionnable) + const handleClickOnActionnable = async (actionnable: string = "", userAction: string = "") => { + setBusy(busyRef.current = true) // TODO: ask Llama2 what to do about it @@ -171,7 +174,7 @@ export default function Main() { let newDialogue = "" try { - newDialogue = await getDialogue({ game, situation, actionnable }) + newDialogue = await getDialogue({ game, situation, userAction }) // console.log(`newDialogue:`, newDialogue) setDialogue(newDialogue) } catch (err) { @@ -180,10 +183,12 @@ export default function Main() { } try { - const newActionnables = await getActionnables({ game, situation, actionnable, newDialogue }) + const newActionnables = await getActionnables({ game, situation, userAction }) console.log(`newActionnables:`, newActionnables) - const newBackground = await getBackground({ game, situation, actionnable, newDialogue, newActionnables }) + // todo rename this background/situation mess + // it should be only one word + const newBackground = await getBackground({ game, situation, userAction, newActionnables }) console.log(`newBackground:`, newBackground) setSituation(newBackground) @@ -267,6 +272,79 @@ export default function Main() { window.location = `${window.location.protocol + "//" + window.location.host + window.location.pathname + '?' + search.toString()}` as any } + const handleSceneEvent = (event: SceneEvent, actionnable?: string) => { + const actionnableName = actionnable || "nothing" + let newEvent = null + let newEventString = "" + if (event === "HoveringNothing") { + newEvent = <>🔎 You are looking at: Nothing + newEventString = `User is looking at nothing.` + } else if (event === "HoveringActionnable") { + newEvent = <>🔎 You are looking at: {actionnableName} + newEventString = `User is looking at "${actionnableName}"` + } else if (event === "ClickOnNothing") { + newEvent = <>🔎 There is nothing here. + newEventString = `User clicked on nothing.` + } else if (event === "ClickOnActionnable") { + newEvent = <>🔎 You have clicked on {actionnableName} + newEventString = `User has clicked on "${actionnableName}"` + } + + if (newEventString && newEventString !== lastEventString) { + console.log(newEventString) + setLastEventString(newEventString) + setLastEvent(newEvent) + } + + if (event === "ClickOnActionnable" || event === "ClickOnNothing") { + handleClickOnActionnable(actionnable, newEventString) + } + } + + const askGameMasterForSomeDialogue = async (userAction: string) => { + await startTransition(async () => { + const game = getGame(gameRef.current) + let newDialogue = "" + try { + newDialogue = await getDialogue({ game, situation, userAction }) + + // try to remove whatever hallucination might come up next + newDialogue = newDialogue.split("As the player")[0] + newDialogue = newDialogue.split("As they use")[0] + + setDialogue(newDialogue) + } catch (err) { + console.log(`failed to generate dialogue (but it's only a nice to have, so..)`) + setDialogue("") + } + }) + } + + const handleInventoryEvent = (event: InventoryEvent, item: InventoryItem, target?: InventoryItem) => { + let newEvent = null + let newEventString = "" + if (newEvent === "Grabbing") { + newEventString = `Player just grabbed "${item.name}".` + newEvent = <>You just grabbed {item.name} + } else if (event === "DroppedOnAnotherItem") { + newEventString = `Player is trying to use those object from their own inventory: "${item.name}" with "${target?.name}". What do you think could the combination of ${item.name} and ${target?.name} lead to? Invent a funny outcome!` + newEvent = <>You tried to combine "{item.name}" with "{target?.name}" + } else if (event === "ClickOnItem") { + newEventString = `Player is inspecting "${item.name}" from their inventory, which has the following description: "${item.description}". Can you invent a funny back story?` + newEvent = <>🔎 You are inspecting "{item.name}". {item.description} + } + + if (newEventString && newEventString !== lastEventString) { + console.log(newEventString) + setLastEventString(newEventString) + setLastEvent(newEvent) + } + + if (event === "DroppedOnAnotherItem" || event === "ClickOnItem") { + askGameMasterForSomeDialogue(newEventString) + } + } + // determine when to show the spinner const isLoading = isBusy || rendered.status === "pending" @@ -322,32 +400,36 @@ export default function Main() { "flex flex-col w-full pt-4 space-y-3 text-gray-50 dark:text-gray-50", getGame(gameRef.current).className // apply the game theme ].join(" ")}> -
-
- {rendered.segments.length - ? 🔎 Try to click on: - : ⌛ Searching in the scene.. - } +
+
{lastEvent}
+
+
+ {rendered.segments.length + ? 💡 Try to click on: + : ⌛ Generating clickable areas.. + } +
+ {clickables.map((clickable, i) => +
+
{clickable}
+ {i < (clickables.length - 1) ?
,
: null} +
)}
- {clickables.map((clickable, i) => -
-
{clickable}
- {i < (clickables.length - 1) ?
,
: null} -
)} -
-
- You are looking at: {hoveredActionnable || "nothing"}
- + -
{dialogue}
+
{dialogue}
) diff --git a/src/app/page.tsx b/src/app/page.tsx index ae60803ca706644b1f60fed6db95b9c3bd1d5d4f..02232b4d13fd7e6bb68f4c6d6549c7448f712c73 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -3,6 +3,7 @@ import Head from "next/head" import Main from "./main" +import { TooltipProvider } from "@/components/ui/tooltip" // https://nextjs.org/docs/pages/building-your-application/optimizing/fonts @@ -18,7 +19,9 @@ export default async function IndexPage({ params: { ownerId } }: { params: { own `dark fixed inset-0 flex flex-col items-center bg-stone-900 text-stone-10 overflow-y-scroll `}> -
+ +
+
) diff --git a/src/app/queries/getActionnables.ts b/src/app/queries/getActionnables.ts index ee70a1ff8f8557b00ae081a2afab588674fdc5c4..256421982950e9b4429ae2247679151c0f26adb5 100644 --- a/src/app/queries/getActionnables.ts +++ b/src/app/queries/getActionnables.ts @@ -9,18 +9,14 @@ import { normalizeActionnables } from "@/lib/normalizeActionnables" export const getActionnables = async ({ game, situation = "", - actionnable = "", - newDialogue = "", - // newActionnables = [], + userAction = "", }: { game: Game; situation: string; - actionnable: string; - newDialogue: string; - // newActionnables: string[]; + userAction: string; }) => { - const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable) + const { currentPrompt, initialPrompt, userSituationPrompt } = getBase({ game, situation, userAction }) const basePrompt = initialPrompt !== currentPrompt ? `Here is some context information about the initial scene: ${initialPrompt}` diff --git a/src/app/queries/getBackground.ts b/src/app/queries/getBackground.ts index b19edd9e7948ecbb71d3f00d6f711299177a6881..1d855bde5cbcbe26a1ca8a693575235076c1b3f0 100644 --- a/src/app/queries/getBackground.ts +++ b/src/app/queries/getBackground.ts @@ -7,18 +7,24 @@ import { predict } from "./predict" export const getBackground = async ({ game, situation = "", - actionnable = "", - newDialogue = "", + userAction = "", newActionnables = [], }: { game: Game; situation: string; - actionnable: string; - newDialogue: string; - newActionnables: string[]; + userAction: string; + newActionnables: string[], }) => { - const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable) + const { + currentPrompt, + initialPrompt, + userSituationPrompt + } = getBase({ + game, + situation, + userAction + }) const basePrompt = initialPrompt !== currentPrompt ? `You must imagine the most plausible next scene, based on where the player was located before and is now, and also what the player did before and are doing now. @@ -33,7 +39,7 @@ Here is the original scene in which the user was located at first, which will in basePrompt, `You are going to receive new information about the current whereabouts of the player.`, `Please write a caption for the next plausible scene to display in intricate details: the environment, lights, era, characters, objects, textures, light etc.`, - `You must include important objects, that the user can click on (eg. characters, doors, vehicles, useful objects).`, + `You MUST include the following important objects that the user can click on: ${newActionnables}.`, `Be straight to the point, and do not say things like "As the player clicks on.." or "the scene shifts to" (the best is not not mention the player at all)` ].filter(item => item).join("\n") }, diff --git a/src/app/queries/getBase.ts b/src/app/queries/getBase.ts index b2085a1fc7153877b2e17f21cbeae05716ae938d..65441d381a8eed812dcefdb067f978b06821f64b 100644 --- a/src/app/queries/getBase.ts +++ b/src/app/queries/getBase.ts @@ -1,13 +1,24 @@ import { Game } from "@/app/games/types" -export const getBase = (game: Game, situation: string = "", actionnable: string = "") => { +export const getBase = ({ + game, + situation = "", + userAction = "", +}: { + game: Game; + situation: string; + userAction: string; +}) => { const initialPrompt = [...game.getScenePrompt()].join(", ") const currentPrompt = situation ? [...game.getScenePrompt(situation)].join(", ") : initialPrompt - const userSituationPrompt = `Player is currently in "${currentPrompt}". Player clicked on the "${actionnable}".` + const userSituationPrompt = [ + `Player is currently in "${currentPrompt}".`, + userAction + ].join(" ") return { initialPrompt, currentPrompt, userSituationPrompt } } \ No newline at end of file diff --git a/src/app/queries/getDialogue.ts b/src/app/queries/getDialogue.ts index f8e495c6a3b89f219a8081dd6ab2085f5c4a230b..c8eea6665803b266d2dca911cedaf334d55a36b6 100644 --- a/src/app/queries/getDialogue.ts +++ b/src/app/queries/getDialogue.ts @@ -8,19 +8,22 @@ import { predict } from "./predict" export const getDialogue = async ({ game, situation = "", - actionnable = "", - // newDialogue = "", - // newActionnables = [], + userAction = "", }: { game: Game; situation: string; - actionnable: string; - // newDialogue: string; - // newActionnables: string[]; + userAction: string; }) => { - const { currentPrompt, initialPrompt, userSituationPrompt } = getBase(game, situation, actionnable) + const { currentPrompt, initialPrompt, userSituationPrompt } = getBase({ game, situation, userAction }) + console.log("DEBUG", { + game, situation, userAction, + currentPrompt, + initialPrompt, + userSituationPrompt, + + }) /* const basePrompt = initialPrompt !== currentPrompt ? `for your information, the initial game panel and scene was: ${initialPrompt}` @@ -40,8 +43,9 @@ Here is the original scene in which the user was located at first, which will in `You are going to receive new information about the current whereabouts and action of the player.`, basePrompt, `You must imagine a funny response to speak in reaction to what the player did, like in some old point and click video games.`, - `Please limit yourself to only a 1 or 2 sentences, please.`, - `Also please don't say things like "Well, well, well", it is annoying.` + `Please only write between 2 to 3 short sentences, please.`, + `Please add a few funny puns and jokes.`, + `But please don't say things like "Well, well, well", it is annoying.` ].filter(item => item).join("\n") }, { diff --git a/src/app/queries/getInventoryItem.ts b/src/app/queries/getInventoryItem.ts new file mode 100644 index 0000000000000000000000000000000000000000..05c9fcaf6e41cc1a7a03d56b31034cdd549dac13 --- /dev/null +++ b/src/app/queries/getInventoryItem.ts @@ -0,0 +1,5 @@ + + +// 3D render of a single coconut, highly detailed, beautiful, white background + +// 3D render of a fishbone, highly detailed, beautiful, pixar style, white background \ No newline at end of file diff --git a/src/app/types.ts b/src/app/types.ts index 0f02c1c6852fd8afece0a8ee4ce46286f56e693c..adaab2893381318dd80d1bbd5db639ffc3a8e88f 100644 --- a/src/app/types.ts +++ b/src/app/types.ts @@ -38,7 +38,17 @@ export interface ImageSegment { score: number } -export type RenderedSceneStatus = 'pending' | 'completed' | 'error' +export type RenderedSceneStatus = + | "pending" + | "completed" + | "error" + +export type SceneEvent = + | "HoveringNothing" + | "HoveringActionnable" + | "ClickOnNothing" + | "ClickOnActionnable" + export interface RenderedScene { renderId: string status: RenderedSceneStatus @@ -46,4 +56,22 @@ export interface RenderedScene { error: string maskUrl: string segments: ImageSegment[] -} \ No newline at end of file +} + +export type InventoryEvent = + | "Grabbing" // grabbed from the inventory, the item is flying over nothing + | "HoverAnItem" // hover an item, without dragging it + | "ClickOnItem" // click on an item, without dragging it + | "HoveringTheScene" // the item is hover the scene, but not on an actionnable + | "HoveringActionnable" // the item is hover a scene actionnable, ready to be dropped + | "DroppedOnActionnable" // the item has been dropped on a scene actionnable + | "HoveringAnotherItem" // the item is hover another inventory item, ready to be dropped + | "DroppedOnAnotherItem" // the item has been dropped on another inventory item + | "DroppedBackToInventory" // the drag & drop is cancelled, the item is back in the inventory + +export interface InventoryItem { + name: string + title: string + caption: string + description: string +} diff --git a/src/components/inventory/draggable-item.tsx b/src/components/inventory/draggable-item.tsx new file mode 100644 index 0000000000000000000000000000000000000000..93680f2ff15a6583168d8eefeb6a3f652aca50f7 --- /dev/null +++ b/src/components/inventory/draggable-item.tsx @@ -0,0 +1,82 @@ + +import Image from "next/image" +import { useDrag, useDrop } from "react-dnd" + +import { Game } from "@/app/games/types" +import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip" +import { InventoryEvent, InventoryItem } from "@/app/types" +import { useEffect } from "react" + +type DropResult = InventoryItem + +export function DraggableItem({ game, item, onEvent }: { + game: Game; + item: InventoryItem; + onEvent: (event: InventoryEvent, item: InventoryItem, target?: InventoryItem) => void +}) { + const [{ isDragging }, drag] = useDrag(() => ({ + type: "item", + item, + end: (item, monitor) => { + const dropResult = monitor.getDropResult() + if (item && dropResult) { + onEvent("DroppedOnAnotherItem", item, dropResult) + } + }, + collect: (monitor) => ({ + isDragging: monitor.isDragging(), + handlerId: monitor.getHandlerId(), + }), + })) + + const [{ isOver, canDrop }, drop] = useDrop({ + accept: "item", + drop: () => (item), + collect: (monitor) => ({ + isOver: monitor.isOver(), + canDrop: monitor.canDrop(), + }), + }) + + useEffect(() => { + if (isDragging) { + onEvent("Grabbing", item) + } else { + onEvent("DroppedBackToInventory", item) + } + }, [isDragging]) + + return ( + + +
onEvent("ClickOnItem", item)} + className={[ + "bg-gray-100 rounded-2xl overflow-hidden", + "transition-all duration-200", + isDragging + ? "brightness-100 scale-125 border border-stone-300 shadow-2xl cursor-grabbing" + : "brightness-90 border-2 shadow-md cursor-grab", + isOver && canDrop + ? "border-stone-100" + : "border-stone-600", + "hover:brightness-100 hover:scale-125 hover:border hover:border-stone-300 hover:shadow-2xl", + ].join(" ")}> +
+ {item.title} +
+
+
+ +

{item.title}

+
+
+ ) +} \ No newline at end of file diff --git a/src/components/inventory/index.tsx b/src/components/inventory/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e66c9f3a3e71f6f844fd681a0bf6d8c937bdf639 --- /dev/null +++ b/src/components/inventory/index.tsx @@ -0,0 +1,29 @@ +import { DndProvider } from "react-dnd" +import { HTML5Backend } from "react-dnd-html5-backend" + +import { Game } from "@/app/games/types" +import { DraggableItem } from "./draggable-item" +import { InventoryEvent, InventoryItem } from "@/app/types" + +export function Inventory({ + game, + onEvent +}: { + game: Game; + onEvent: (event: InventoryEvent, item: InventoryItem, target?: InventoryItem) => void +}) { + return ( + +
+ {game.inventory.map(item => ( + + ))} +
+
+ ) +} \ No newline at end of file diff --git a/src/components/business/cartesian-image.tsx b/src/components/renderer/cartesian-image.tsx similarity index 100% rename from src/components/business/cartesian-image.tsx rename to src/components/renderer/cartesian-image.tsx diff --git a/src/components/business/cartesian-video.tsx b/src/components/renderer/cartesian-video.tsx similarity index 100% rename from src/components/business/cartesian-video.tsx rename to src/components/renderer/cartesian-video.tsx diff --git a/src/components/business/renderer.tsx b/src/components/renderer/index.tsx similarity index 92% rename from src/components/business/renderer.tsx rename to src/components/renderer/index.tsx index 73b0658ea58b4b32eb5b700439b70cb5cb804c39..fa427d4ccc2b459b6ba60d6e2a931e7733728756 100644 --- a/src/components/business/renderer.tsx +++ b/src/components/renderer/index.tsx @@ -1,27 +1,25 @@ import { useEffect, useRef, useState } from "react" -import { ImageSegment, RenderedScene } from "@/app/types" +import { ImageSegment, RenderedScene, SceneEvent } from "@/app/types" import { ProgressBar } from "../misc/progress" import { Game } from "@/app/games/types" -import { Engine, EngineType } from "@/app/engines" +import { Engine } from "@/app/engines" import { CartesianImage } from "./cartesian-image" import { SceneEventHandler, SceneEventType } from "./types" import { CartesianVideo } from "./cartesian-video" import { SphericalImage } from "./spherical-image" import { useImageDimension } from "@/lib/useImageDimension" -export const Renderer = ({ +export const SceneRenderer = ({ rendered, - onUserAction, - onUserHover, + onEvent, isLoading, game, engine, debug }: { rendered: RenderedScene - onUserAction: (actionnable: string) => void - onUserHover: (actionnable: string) => void + onEvent: (event: SceneEvent, actionnable?: string) => void isLoading: boolean game: Game engine: Engine @@ -69,8 +67,7 @@ export const Renderer = ({ const getSegmentAt = (x: number, y: number): ImageSegment => { if (!contextRef.current) throw new Error("Unable to get context from canvas"); - if (!rendered.maskUrl) throw new Error("Mask is undefined"); - + let closestSegment: ImageSegment = { id: 0, box: [], @@ -109,7 +106,8 @@ export const Renderer = ({ // note: coordinates must be between 0 and 1 const handleMouseEvent: SceneEventHandler = async (type: SceneEventType, relativeX: number, relativeY: number) => { if (!contextRef.current) return; // Return early if mask image has not been loaded yet - + if (!rendered.maskUrl) return; + if (isLoading) { // we ignore all user interactions return @@ -119,7 +117,7 @@ export const Renderer = ({ // so if we click anywhere bug there are no segments, // we inform the rest of the app by passing nothing if (type === "click" && rendered.segments.length == 0) { - onUserAction("nothing, to trigger a scene reload") + onEvent("ClickOnNothing") return } @@ -144,12 +142,16 @@ export const Renderer = ({ return } console.log("User clicked on " + newSegment.label) - onUserAction(actionnable) + onEvent("ClickOnActionnable", actionnable) } else { // only trigger hover events if there are segments, // otherwise it's best to stay silent if (rendered.segments.length) { - onUserHover(actionnable) + if (actionnable) { + onEvent("HoveringActionnable", actionnable) + } else { + onEvent("HoveringNothing") + } } } }; @@ -216,7 +218,7 @@ export const Renderer = ({ {isLoading - ?
+ ?
, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)) +TooltipContent.displayName = TooltipPrimitive.Content.displayName + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }