diff --git a/client/package-lock.json b/client/package-lock.json index 681b62e..cd08327 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -6,6 +6,8 @@ "": { "name": "shadowdark-client", "dependencies": { + "@3d-dice/dice-box": "^1.1.4", + "@3d-dice/dice-box-threejs": "^0.0.12", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.1.1", @@ -19,6 +21,30 @@ "vite": "^6.0.0" } }, + "node_modules/@3d-dice/dice-box": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@3d-dice/dice-box/-/dice-box-1.1.4.tgz", + "integrity": "sha512-W8evh0LlCx/sorPS00cGZJO+/3I8g5eMfDqFAKAIUXF+/XVTP06bhgHSNFOCvLzWbdbEJX5za9QxB0ulDvfxyA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@babylonjs/core": "5.57.1", + "@babylonjs/loaders": "5.57.1", + "@babylonjs/materials": "5.57.1", + "copy-dir": "^1.3.0", + "node-abort-controller": "^3.1.1" + } + }, + "node_modules/@3d-dice/dice-box-threejs": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@3d-dice/dice-box-threejs/-/dice-box-threejs-0.0.12.tgz", + "integrity": "sha512-Bau5UizUunZS9+A6zgGeZecEJotSLEI6YvmYTosvvdhRxv92xo89aIvKYQb6xqdx/AqjHdGENJmqBOadlFL9kA==", + "license": "MIT", + "dependencies": { + "cannon-es": "^0.20.0", + "three": "^0.143.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -301,6 +327,31 @@ "node": ">=6.9.0" } }, + "node_modules/@babylonjs/core": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@babylonjs/core/-/core-5.57.1.tgz", + "integrity": "sha512-k8U+SFPVGvHgeNr651nxZL26iVCmTzjmRrdbQa0BGas+lg8PIV/tfhN4uTeWWQeRFLvjbkcHA5qD8x/Xk3EpMQ==", + "license": "Apache-2.0" + }, + "node_modules/@babylonjs/loaders": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@babylonjs/loaders/-/loaders-5.57.1.tgz", + "integrity": "sha512-DHk0iOwJgnTcj8vI+cQVzpiUvWGJvYqWyZxsf7nzhbeND+ZwNWSG0AelaGbGHpWTaDSd/DjUcoWVZuT4Cg6/Xg==", + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^5.22.0", + "babylonjs-gltf2interface": "^5.22.0" + } + }, + "node_modules/@babylonjs/materials": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/@babylonjs/materials/-/materials-5.57.1.tgz", + "integrity": "sha512-NLdR6eGUr+wFqie937HRWsnaWPeECpjOrYDGvjjYDg08VAcIC3YyctAuQxv8rId7BoDttkUd8Ey/IZ5d/9H7GA==", + "license": "Apache-2.0", + "peerDependencies": { + "@babylonjs/core": "^5.22.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", @@ -1257,6 +1308,13 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/babylonjs-gltf2interface": { + "version": "5.57.1", + "resolved": "https://registry.npmjs.org/babylonjs-gltf2interface/-/babylonjs-gltf2interface-5.57.1.tgz", + "integrity": "sha512-RZnaKfJ6Q/AYLdIjBYMRxCW/HPEC8jabAL1U8wJ0KVziw6NSbSV6S80S22fUCPTyaZ7nCekn1TYg1IPmJ/eA6w==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/baseline-browser-mapping": { "version": "2.10.16", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.16.tgz", @@ -1325,6 +1383,12 @@ ], "license": "CC-BY-4.0" }, + "node_modules/cannon-es": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/cannon-es/-/cannon-es-0.20.0.tgz", + "integrity": "sha512-eZhWTZIkFOnMAJOgfXJa9+b3kVlvG+FX4mdkpePev/w/rP5V8NRquGyEozcjPfEoXUlb+p7d9SUcmDSn14prOA==", + "license": "MIT" + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1345,6 +1409,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/copy-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz", + "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw==", + "license": "MIT" + }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", @@ -1572,6 +1642,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" + }, "node_modules/node-releases": { "version": "2.0.37", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz", @@ -1809,6 +1885,12 @@ "node": ">=0.10.0" } }, + "node_modules/three": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.143.0.tgz", + "integrity": "sha512-oKcAGYHhJ46TGEuHjodo2n6TY2R6lbvrkp+feKZxqsUL/WkH7GKKaeu6RHeyb2Xjfk2dPLRKLsOP0KM2VgT8Zg==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", diff --git a/client/package.json b/client/package.json index 8edc8cf..2c53eb0 100644 --- a/client/package.json +++ b/client/package.json @@ -7,6 +7,8 @@ "preview": "vite preview" }, "dependencies": { + "@3d-dice/dice-box": "^1.1.4", + "@3d-dice/dice-box-threejs": "^0.0.12", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^7.1.1", diff --git a/client/public/dice/sounds/dicehit/dicehit_coin1.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin1.mp3 new file mode 100755 index 0000000..d07a721 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin1.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_coin2.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin2.mp3 new file mode 100755 index 0000000..de52f9b Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin2.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_coin3.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin3.mp3 new file mode 100755 index 0000000..712a471 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin3.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_coin4.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin4.mp3 new file mode 100755 index 0000000..1dcbe59 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin4.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_coin5.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin5.mp3 new file mode 100755 index 0000000..265b6b9 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin5.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_coin6.mp3 b/client/public/dice/sounds/dicehit/dicehit_coin6.mp3 new file mode 100755 index 0000000..f9a06d4 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_coin6.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal1.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal1.mp3 new file mode 100755 index 0000000..077c478 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal1.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal10.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal10.mp3 new file mode 100755 index 0000000..255eea2 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal10.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal11.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal11.mp3 new file mode 100755 index 0000000..0bab2a8 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal11.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal12.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal12.mp3 new file mode 100755 index 0000000..7f08549 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal12.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal2.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal2.mp3 new file mode 100755 index 0000000..f03b98c Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal2.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal3.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal3.mp3 new file mode 100755 index 0000000..a5dd435 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal3.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal4.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal4.mp3 new file mode 100755 index 0000000..26c1803 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal4.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal5.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal5.mp3 new file mode 100755 index 0000000..a5544be Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal5.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal6.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal6.mp3 new file mode 100755 index 0000000..c07180f Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal6.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal7.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal7.mp3 new file mode 100755 index 0000000..a2aecde Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal7.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal8.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal8.mp3 new file mode 100755 index 0000000..b26476f Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal8.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_metal9.mp3 b/client/public/dice/sounds/dicehit/dicehit_metal9.mp3 new file mode 100755 index 0000000..5d9e90b Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_metal9.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic1.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic1.mp3 new file mode 100755 index 0000000..a100d70 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic1.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic10.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic10.mp3 new file mode 100755 index 0000000..406c71b Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic10.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic11.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic11.mp3 new file mode 100755 index 0000000..a49e877 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic11.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic12.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic12.mp3 new file mode 100755 index 0000000..19bb720 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic12.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic13.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic13.mp3 new file mode 100755 index 0000000..5611701 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic13.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic14.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic14.mp3 new file mode 100755 index 0000000..706b2fd Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic14.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic15.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic15.mp3 new file mode 100755 index 0000000..f0cf3a4 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic15.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic2.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic2.mp3 new file mode 100755 index 0000000..9d4eb27 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic2.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic3.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic3.mp3 new file mode 100755 index 0000000..ad00956 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic3.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic4.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic4.mp3 new file mode 100755 index 0000000..3359d86 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic4.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic5.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic5.mp3 new file mode 100755 index 0000000..f0da2f1 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic5.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic6.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic6.mp3 new file mode 100755 index 0000000..a812b8a Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic6.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic7.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic7.mp3 new file mode 100755 index 0000000..2a66e45 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic7.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic8.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic8.mp3 new file mode 100755 index 0000000..506f2b9 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic8.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_plastic9.mp3 b/client/public/dice/sounds/dicehit/dicehit_plastic9.mp3 new file mode 100755 index 0000000..7992067 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_plastic9.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood1.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood1.mp3 new file mode 100755 index 0000000..9c5bb18 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood1.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood10.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood10.mp3 new file mode 100755 index 0000000..46a3746 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood10.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood11.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood11.mp3 new file mode 100755 index 0000000..c2a852e Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood11.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood12.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood12.mp3 new file mode 100755 index 0000000..3d66478 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood12.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood2.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood2.mp3 new file mode 100755 index 0000000..6c402de Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood2.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood3.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood3.mp3 new file mode 100755 index 0000000..835db18 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood3.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood4.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood4.mp3 new file mode 100755 index 0000000..0f9c7e5 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood4.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood5.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood5.mp3 new file mode 100755 index 0000000..5b6f0da Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood5.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood6.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood6.mp3 new file mode 100755 index 0000000..921b1ad Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood6.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood7.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood7.mp3 new file mode 100755 index 0000000..1029332 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood7.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood8.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood8.mp3 new file mode 100755 index 0000000..8456d75 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood8.mp3 differ diff --git a/client/public/dice/sounds/dicehit/dicehit_wood9.mp3 b/client/public/dice/sounds/dicehit/dicehit_wood9.mp3 new file mode 100755 index 0000000..601afb0 Binary files /dev/null and b/client/public/dice/sounds/dicehit/dicehit_wood9.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt1.mp3 b/client/public/dice/sounds/surfaces/surface_felt1.mp3 new file mode 100755 index 0000000..b5d298d Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt1.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt2.mp3 b/client/public/dice/sounds/surfaces/surface_felt2.mp3 new file mode 100755 index 0000000..d187453 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt2.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt3.mp3 b/client/public/dice/sounds/surfaces/surface_felt3.mp3 new file mode 100755 index 0000000..2876c87 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt3.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt4.mp3 b/client/public/dice/sounds/surfaces/surface_felt4.mp3 new file mode 100755 index 0000000..62ccd10 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt4.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt5.mp3 b/client/public/dice/sounds/surfaces/surface_felt5.mp3 new file mode 100755 index 0000000..dbb15d1 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt5.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt6.mp3 b/client/public/dice/sounds/surfaces/surface_felt6.mp3 new file mode 100755 index 0000000..dd97670 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt6.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_felt7.mp3 b/client/public/dice/sounds/surfaces/surface_felt7.mp3 new file mode 100755 index 0000000..2e55a83 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_felt7.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal1.mp3 b/client/public/dice/sounds/surfaces/surface_metal1.mp3 new file mode 100755 index 0000000..fca44de Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal1.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal2.mp3 b/client/public/dice/sounds/surfaces/surface_metal2.mp3 new file mode 100755 index 0000000..aacf2c6 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal2.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal3.mp3 b/client/public/dice/sounds/surfaces/surface_metal3.mp3 new file mode 100755 index 0000000..5d2bafc Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal3.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal4.mp3 b/client/public/dice/sounds/surfaces/surface_metal4.mp3 new file mode 100755 index 0000000..47b9afd Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal4.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal5.mp3 b/client/public/dice/sounds/surfaces/surface_metal5.mp3 new file mode 100755 index 0000000..6103002 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal5.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal6.mp3 b/client/public/dice/sounds/surfaces/surface_metal6.mp3 new file mode 100755 index 0000000..ba60148 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal6.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal7.mp3 b/client/public/dice/sounds/surfaces/surface_metal7.mp3 new file mode 100755 index 0000000..e4b87b7 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal7.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal8.mp3 b/client/public/dice/sounds/surfaces/surface_metal8.mp3 new file mode 100755 index 0000000..adc17f8 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal8.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_metal9.mp3 b/client/public/dice/sounds/surfaces/surface_metal9.mp3 new file mode 100755 index 0000000..fa4643e Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_metal9.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table1.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table1.mp3 new file mode 100755 index 0000000..199baca Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table1.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table2.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table2.mp3 new file mode 100755 index 0000000..5c0cf02 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table2.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table3.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table3.mp3 new file mode 100755 index 0000000..ef9e8c0 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table3.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table4.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table4.mp3 new file mode 100755 index 0000000..fbf6c1b Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table4.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table5.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table5.mp3 new file mode 100755 index 0000000..34aee14 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table5.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table6.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table6.mp3 new file mode 100755 index 0000000..869d6fd Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table6.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_table7.mp3 b/client/public/dice/sounds/surfaces/surface_wood_table7.mp3 new file mode 100755 index 0000000..1464785 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_table7.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray1.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray1.mp3 new file mode 100755 index 0000000..e146ed3 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray1.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray2.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray2.mp3 new file mode 100755 index 0000000..556e73f Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray2.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray3.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray3.mp3 new file mode 100755 index 0000000..68da166 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray3.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray4.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray4.mp3 new file mode 100755 index 0000000..3513cf0 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray4.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray5.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray5.mp3 new file mode 100755 index 0000000..77d91eb Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray5.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray6.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray6.mp3 new file mode 100755 index 0000000..fc28534 Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray6.mp3 differ diff --git a/client/public/dice/sounds/surfaces/surface_wood_tray7.mp3 b/client/public/dice/sounds/surfaces/surface_wood_tray7.mp3 new file mode 100755 index 0000000..b76878f Binary files /dev/null and b/client/public/dice/sounds/surfaces/surface_wood_tray7.mp3 differ diff --git a/client/public/dice/textures/astral.webp b/client/public/dice/textures/astral.webp new file mode 100755 index 0000000..83a1c23 Binary files /dev/null and b/client/public/dice/textures/astral.webp differ diff --git a/client/public/dice/textures/bronze01.webp b/client/public/dice/textures/bronze01.webp new file mode 100755 index 0000000..cbc45c3 Binary files /dev/null and b/client/public/dice/textures/bronze01.webp differ diff --git a/client/public/dice/textures/bronze02.webp b/client/public/dice/textures/bronze02.webp new file mode 100755 index 0000000..241fcce Binary files /dev/null and b/client/public/dice/textures/bronze02.webp differ diff --git a/client/public/dice/textures/bronze03.webp b/client/public/dice/textures/bronze03.webp new file mode 100755 index 0000000..044d211 Binary files /dev/null and b/client/public/dice/textures/bronze03.webp differ diff --git a/client/public/dice/textures/bronze03a.webp b/client/public/dice/textures/bronze03a.webp new file mode 100755 index 0000000..05e11b2 Binary files /dev/null and b/client/public/dice/textures/bronze03a.webp differ diff --git a/client/public/dice/textures/bronze03b.webp b/client/public/dice/textures/bronze03b.webp new file mode 100755 index 0000000..81779c0 Binary files /dev/null and b/client/public/dice/textures/bronze03b.webp differ diff --git a/client/public/dice/textures/bronze04.webp b/client/public/dice/textures/bronze04.webp new file mode 100755 index 0000000..0bfa37c Binary files /dev/null and b/client/public/dice/textures/bronze04.webp differ diff --git a/client/public/dice/textures/cheetah.webp b/client/public/dice/textures/cheetah.webp new file mode 100755 index 0000000..29c625a Binary files /dev/null and b/client/public/dice/textures/cheetah.webp differ diff --git a/client/public/dice/textures/cloudy.alt.webp b/client/public/dice/textures/cloudy.alt.webp new file mode 100755 index 0000000..575ad27 Binary files /dev/null and b/client/public/dice/textures/cloudy.alt.webp differ diff --git a/client/public/dice/textures/cloudy.webp b/client/public/dice/textures/cloudy.webp new file mode 100755 index 0000000..b73592c Binary files /dev/null and b/client/public/dice/textures/cloudy.webp differ diff --git a/client/public/dice/textures/dragon-bump.webp b/client/public/dice/textures/dragon-bump.webp new file mode 100755 index 0000000..81591a5 Binary files /dev/null and b/client/public/dice/textures/dragon-bump.webp differ diff --git a/client/public/dice/textures/dragon.webp b/client/public/dice/textures/dragon.webp new file mode 100755 index 0000000..d5caed7 Binary files /dev/null and b/client/public/dice/textures/dragon.webp differ diff --git a/client/public/dice/textures/feather-bump.webp b/client/public/dice/textures/feather-bump.webp new file mode 100755 index 0000000..781f297 Binary files /dev/null and b/client/public/dice/textures/feather-bump.webp differ diff --git a/client/public/dice/textures/feather.webp b/client/public/dice/textures/feather.webp new file mode 100755 index 0000000..a505e1f Binary files /dev/null and b/client/public/dice/textures/feather.webp differ diff --git a/client/public/dice/textures/fire.webp b/client/public/dice/textures/fire.webp new file mode 100755 index 0000000..653044f Binary files /dev/null and b/client/public/dice/textures/fire.webp differ diff --git a/client/public/dice/textures/glitter-alpha.webp b/client/public/dice/textures/glitter-alpha.webp new file mode 100755 index 0000000..fef86f0 Binary files /dev/null and b/client/public/dice/textures/glitter-alpha.webp differ diff --git a/client/public/dice/textures/glitter-bump.webp b/client/public/dice/textures/glitter-bump.webp new file mode 100755 index 0000000..2070ed9 Binary files /dev/null and b/client/public/dice/textures/glitter-bump.webp differ diff --git a/client/public/dice/textures/glitter.webp b/client/public/dice/textures/glitter.webp new file mode 100755 index 0000000..df7cdbe Binary files /dev/null and b/client/public/dice/textures/glitter.webp differ diff --git a/client/public/dice/textures/ice.webp b/client/public/dice/textures/ice.webp new file mode 100755 index 0000000..47250b5 Binary files /dev/null and b/client/public/dice/textures/ice.webp differ diff --git a/client/public/dice/textures/leopard.webp b/client/public/dice/textures/leopard.webp new file mode 100755 index 0000000..841604a Binary files /dev/null and b/client/public/dice/textures/leopard.webp differ diff --git a/client/public/dice/textures/lizard-bump.webp b/client/public/dice/textures/lizard-bump.webp new file mode 100755 index 0000000..7f5f08c Binary files /dev/null and b/client/public/dice/textures/lizard-bump.webp differ diff --git a/client/public/dice/textures/lizard.webp b/client/public/dice/textures/lizard.webp new file mode 100755 index 0000000..095c464 Binary files /dev/null and b/client/public/dice/textures/lizard.webp differ diff --git a/client/public/dice/textures/marble.webp b/client/public/dice/textures/marble.webp new file mode 100755 index 0000000..1bed836 Binary files /dev/null and b/client/public/dice/textures/marble.webp differ diff --git a/client/public/dice/textures/metal-bump.webp b/client/public/dice/textures/metal-bump.webp new file mode 100755 index 0000000..cef36e0 Binary files /dev/null and b/client/public/dice/textures/metal-bump.webp differ diff --git a/client/public/dice/textures/metal.webp b/client/public/dice/textures/metal.webp new file mode 100755 index 0000000..7c7c1ee Binary files /dev/null and b/client/public/dice/textures/metal.webp differ diff --git a/client/public/dice/textures/noise-thin-film.webp b/client/public/dice/textures/noise-thin-film.webp new file mode 100755 index 0000000..62c78bb Binary files /dev/null and b/client/public/dice/textures/noise-thin-film.webp differ diff --git a/client/public/dice/textures/noise.webp b/client/public/dice/textures/noise.webp new file mode 100755 index 0000000..35a2efd Binary files /dev/null and b/client/public/dice/textures/noise.webp differ diff --git a/client/public/dice/textures/paper-bump.webp b/client/public/dice/textures/paper-bump.webp new file mode 100755 index 0000000..8167a0e Binary files /dev/null and b/client/public/dice/textures/paper-bump.webp differ diff --git a/client/public/dice/textures/paper.webp b/client/public/dice/textures/paper.webp new file mode 100755 index 0000000..1105919 Binary files /dev/null and b/client/public/dice/textures/paper.webp differ diff --git a/client/public/dice/textures/skulls.webp b/client/public/dice/textures/skulls.webp new file mode 100755 index 0000000..8b02099 Binary files /dev/null and b/client/public/dice/textures/skulls.webp differ diff --git a/client/public/dice/textures/speckles.webp b/client/public/dice/textures/speckles.webp new file mode 100755 index 0000000..85b3033 Binary files /dev/null and b/client/public/dice/textures/speckles.webp differ diff --git a/client/public/dice/textures/stainedglass-bump.webp b/client/public/dice/textures/stainedglass-bump.webp new file mode 100755 index 0000000..3aadc85 Binary files /dev/null and b/client/public/dice/textures/stainedglass-bump.webp differ diff --git a/client/public/dice/textures/stainedglass.webp b/client/public/dice/textures/stainedglass.webp new file mode 100755 index 0000000..46f1b53 Binary files /dev/null and b/client/public/dice/textures/stainedglass.webp differ diff --git a/client/public/dice/textures/stars.webp b/client/public/dice/textures/stars.webp new file mode 100755 index 0000000..18967f0 Binary files /dev/null and b/client/public/dice/textures/stars.webp differ diff --git a/client/public/dice/textures/stone.webp b/client/public/dice/textures/stone.webp new file mode 100755 index 0000000..376d205 Binary files /dev/null and b/client/public/dice/textures/stone.webp differ diff --git a/client/public/dice/textures/tiger.webp b/client/public/dice/textures/tiger.webp new file mode 100755 index 0000000..c31658c Binary files /dev/null and b/client/public/dice/textures/tiger.webp differ diff --git a/client/public/dice/textures/water.webp b/client/public/dice/textures/water.webp new file mode 100755 index 0000000..5f85bad Binary files /dev/null and b/client/public/dice/textures/water.webp differ diff --git a/client/public/dice/textures/wood.webp b/client/public/dice/textures/wood.webp new file mode 100755 index 0000000..65727a0 Binary files /dev/null and b/client/public/dice/textures/wood.webp differ diff --git a/client/src/components/DiceButton.module.css b/client/src/components/DiceButton.module.css index 68074d9..2c87cad 100644 --- a/client/src/components/DiceButton.module.css +++ b/client/src/components/DiceButton.module.css @@ -32,18 +32,22 @@ } .btn.crit { - border-color: var(--crit); - color: var(--crit); + border-color: var(--danger); + color: var(--danger); + background: rgba(var(--danger-rgb), 0.15); animation: critPulse 1s ease-in-out infinite; - box-shadow: 0 0 8px rgba(var(--crit-rgb), 0.3); } @keyframes critPulse { 0%, 100% { - box-shadow: 0 0 4px rgba(var(--crit-rgb), 0.3); + box-shadow: + 0 0 6px rgba(var(--danger-rgb), 0.5), + inset 0 0 4px rgba(var(--danger-rgb), 0.25); } 50% { - box-shadow: 0 0 12px rgba(var(--crit-rgb), 0.6); + box-shadow: + 0 0 16px rgba(var(--danger-rgb), 0.8), + inset 0 0 6px rgba(var(--danger-rgb), 0.4); } } diff --git a/client/src/components/DiceTray.module.css b/client/src/components/DiceTray.module.css new file mode 100644 index 0000000..883e6be --- /dev/null +++ b/client/src/components/DiceTray.module.css @@ -0,0 +1,18 @@ +.tray { + position: fixed; + inset: 0; + z-index: 500; + pointer-events: none; + opacity: 0; + transition: opacity 0.3s ease; +} + +.tray.active { + pointer-events: auto; + opacity: 1; +} + +.tray :global(canvas) { + width: 100% !important; + height: 100% !important; +} diff --git a/client/src/components/DiceTray.tsx b/client/src/components/DiceTray.tsx new file mode 100644 index 0000000..51ee3f9 --- /dev/null +++ b/client/src/components/DiceTray.tsx @@ -0,0 +1,177 @@ +import { useEffect, useRef } from "react"; +import styles from "./DiceTray.module.css"; + +interface DiceRoll { + /** Original dice expression, e.g. "1d20+3", "2d6+1" */ + expression: string; + /** Individual die values from the server */ + rolls: number[]; + /** Character's HSL color string, e.g. "hsl(210, 70%, 50%)" */ + characterColor?: string; + /** Unique ID to trigger re-rolls of the same expression */ + id: number; +} + +interface DiceTrayProps { + roll: DiceRoll | null; + onAnimationComplete?: () => void; +} + +interface DiceBoxThree { + roll: (notation: string) => Promise; + clearDice: () => void; + theme_customColorset: Record | null; + loadTheme: (config: Record) => Promise; + DiceColors: { makeColorSet: (c: Record) => Promise }; + DiceFactory: { applyColorSet: (c: unknown) => void }; +} + +export default function DiceTray({ roll, onAnimationComplete }: DiceTrayProps) { + const diceBoxRef = useRef(null); + const initRef = useRef(false); + const containerRef = useRef(null); + const clearTimerRef = useRef>(); + const lastColorRef = useRef(""); + const onCompleteRef = useRef(onAnimationComplete); + onCompleteRef.current = onAnimationComplete; + + useEffect(() => { + if (initRef.current) return; + initRef.current = true; + + import("@3d-dice/dice-box-threejs") + .then(async ({ default: DiceBox }) => { + const box = new DiceBox("#dice-tray", { + assetPath: "/dice/", + theme_customColorset: { + foreground: "#FFFFFF", + background: "#8B2020", + outline: "#FFFFFF", + edge: "#4A0E0E", + texture: "stone", + material: "metal", + }, + theme_surface: "default", + gravity_multiplier: 400, + light_intensity: 1.0, + baseScale: 140, + strength: 2, + shadows: true, + onRollComplete: () => { + onCompleteRef.current?.(); + clearTimerRef.current = setTimeout(() => { + box.clearDice(); + if (containerRef.current) { + containerRef.current.classList.remove(styles.active); + } + }, 2500); + }, + }); + + await box.initialize(); + diceBoxRef.current = box as DiceBoxThree; + }) + .catch((err) => { + console.error("Failed to load dice-box-threejs:", err); + }); + + return () => { + if (clearTimerRef.current) clearTimeout(clearTimerRef.current); + }; + }, []); + + useEffect(() => { + if (!roll || !diceBoxRef.current) return; + + const notation = buildNotation(roll.expression, roll.rolls); + if (!notation) return; + + if (clearTimerRef.current) clearTimeout(clearTimerRef.current); + + if (containerRef.current) { + containerRef.current.classList.add(styles.active); + } + + const box = diceBoxRef.current; + const bgColor = roll.characterColor + ? hslToHex(roll.characterColor) + : "#8B2020"; + + // Update dice color if character changed + if (bgColor !== lastColorRef.current) { + lastColorRef.current = bgColor; + const darkBg = darken(bgColor, 0.3); + const colorset = { + foreground: "#FFFFFF", + background: darkBg, + outline: "#FFFFFF", + edge: darken(bgColor, 0.5), + texture: "stone", + material: "metal", + }; + box.theme_customColorset = colorset; + box.DiceColors.makeColorSet(colorset).then((cs) => { + box.DiceFactory.applyColorSet(cs); + box.roll(notation); + }); + } else { + box.roll(notation); + } + }, [roll]); + + return
; +} + +function buildNotation(expression: string, rolls: number[]): string | null { + const match = expression.match(/(\d*)d(\d+)/i); + if (!match) return null; + + const sides = parseInt(match[2]); + const validSides = [4, 6, 8, 10, 12, 20, 100]; + if (!validSides.includes(sides)) return null; + + if (rolls.length === 0) return null; + + const count = rolls.length; + const values = rolls.join(","); + + return `${count}d${sides}@${values}`; +} + +/** Convert an HSL string like "hsl(210, 70%, 50%)" to a hex color */ +function hslToHex(hsl: string): string { + const match = hsl.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/); + if (!match) return "#8B2020"; + + const h = parseInt(match[1]) / 360; + const s = parseInt(match[2]) / 100; + const l = parseInt(match[3]) / 100; + + const hue2rgb = (p: number, q: number, t: number) => { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + }; + + const q = l < 0.5 ? l * (1 + s) : l + s - l * s; + const p = 2 * l - q; + const r = Math.round(hue2rgb(p, q, h + 1 / 3) * 255); + const g = Math.round(hue2rgb(p, q, h) * 255); + const b = Math.round(hue2rgb(p, q, h - 1 / 3) * 255); + + return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`; +} + +/** Darken a hex color by a factor (0 = no change, 1 = black) */ +function darken(hex: string, factor: number): string { + const r = parseInt(hex.slice(1, 3), 16); + const g = parseInt(hex.slice(3, 5), 16); + const b = parseInt(hex.slice(5, 7), 16); + const dr = Math.round(r * (1 - factor)); + const dg = Math.round(g * (1 - factor)); + const db = Math.round(b * (1 - factor)); + return `#${((1 << 24) + (dr << 16) + (dg << 8) + db).toString(16).slice(1)}`; +} diff --git a/client/src/components/RollEntry.module.css b/client/src/components/RollEntry.module.css index d014ed5..f65458c 100644 --- a/client/src/components/RollEntry.module.css +++ b/client/src/components/RollEntry.module.css @@ -25,14 +25,14 @@ .card.nat20 { border-color: var(--crit); - background: linear-gradient( - 135deg, - rgba(40, 35, 15, 0.9), - rgba(24, 21, 16, 0.9) - ); + background-color: var(--bg-roll-entry); + background-image: var(--texture-surface); + background-size: 256px 256px; + background-repeat: repeat; box-shadow: - 0 0 12px rgba(var(--crit-rgb), 0.15), - 0 2px 6px rgba(var(--shadow-rgb), 0.3); + 0 0 12px rgba(var(--crit-rgb), 0.25), + 0 2px 6px rgba(var(--shadow-rgb), 0.3), + inset 0 0 20px rgba(var(--crit-rgb), 0.08); } .card.nat20 .total { diff --git a/client/src/dice-box.d.ts b/client/src/dice-box.d.ts new file mode 100644 index 0000000..3bbb17d --- /dev/null +++ b/client/src/dice-box.d.ts @@ -0,0 +1,61 @@ +declare module "@3d-dice/dice-box" { + interface DiceBoxConfig { + container?: string; + assetPath?: string; + theme?: string; + themeColor?: string; + scale?: number; + enableShadows?: boolean; + shadowTransparency?: number; + lightIntensity?: number; + onRollComplete?: (results: unknown[]) => void; + onDieComplete?: (result: unknown) => void; + } + + class DiceBox { + constructor(config: DiceBoxConfig); + init(): Promise; + roll(notation: string): Promise; + add(notation: string): Promise; + clear(): void; + show(): void; + hide(): void; + updateConfig(config: Partial): void; + } + + export default DiceBox; +} + +declare module "@3d-dice/dice-box-threejs" { + interface DiceBoxThreeConfig { + assetPath?: string; + shadows?: boolean; + theme_colorset?: string; + theme_texture?: string; + theme_material?: string; + theme_surface?: string; + theme_customColorset?: Record | null; + gravity_multiplier?: number; + light_intensity?: number; + baseScale?: number; + strength?: number; + onRollComplete?: (results: unknown[]) => void; + } + + class DiceBox { + constructor(container: string, config?: DiceBoxThreeConfig); + initialize(): Promise; + roll(notation: string): Promise; + clearDice(): void; + loadTheme(config: Record): Promise; + theme_customColorset: Record | null; + DiceColors: { + makeColorSet(c: Record): Promise; + }; + DiceFactory: { + applyColorSet(c: unknown): void; + }; + } + + export default DiceBox; +} diff --git a/client/src/pages/CampaignView.module.css b/client/src/pages/CampaignView.module.css index 12b1603..253b795 100644 --- a/client/src/pages/CampaignView.module.css +++ b/client/src/pages/CampaignView.module.css @@ -9,6 +9,25 @@ padding-right: 0.5rem; position: relative; min-width: 0; + scrollbar-width: thin; + scrollbar-color: rgba(var(--gold-rgb), 0.2) transparent; +} + +.main::-webkit-scrollbar { + width: 6px; +} + +.main::-webkit-scrollbar-track { + background: transparent; +} + +.main::-webkit-scrollbar-thumb { + background: rgba(var(--gold-rgb), 0.2); + border-radius: 3px; +} + +.main::-webkit-scrollbar-thumb:hover { + background: rgba(var(--gold-rgb), 0.35); } @media (max-width: 768px) { diff --git a/client/src/pages/CampaignView.tsx b/client/src/pages/CampaignView.tsx index 5e21394..697dc0e 100644 --- a/client/src/pages/CampaignView.tsx +++ b/client/src/pages/CampaignView.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useParams, Link } from "react-router-dom"; import socket from "../socket"; import { @@ -17,6 +17,7 @@ import type { Character, Gear, Talent, GameItem, RollResult } from "../types"; import CharacterCard from "../components/CharacterCard"; import CharacterDetail from "../components/CharacterDetail"; import RollLog from "../components/RollLog"; +import DiceTray from "../components/DiceTray"; import styles from "./CampaignView.module.css"; const CLASSES = ["Fighter", "Priest", "Thief", "Wizard"]; @@ -37,6 +38,13 @@ export default function CampaignView() { const [rolls, setRolls] = useState([]); const [freshIds, setFreshIds] = useState>(new Set()); const [critKeys, setCritKeys] = useState>(new Set()); + const [diceRoll, setDiceRoll] = useState<{ + expression: string; + rolls: number[]; + characterColor?: string; + id: number; + } | null>(null); + const pendingRollRef = useRef(null); // Fetch characters and join socket room useEffect(() => { @@ -48,6 +56,43 @@ export default function CampaignView() { }; }, [campaignId]); + function showRollInLog(roll: RollResult) { + setRolls((prev) => [roll, ...prev].slice(0, 50)); + setFreshIds((prev) => new Set(prev).add(roll.id)); + setTimeout(() => { + setFreshIds((prev) => { + const next = new Set(prev); + next.delete(roll.id); + return next; + }); + }, 2000); + + // Track crits by character+weapon key + if (roll.nat20 && roll.character_id && roll.label.includes("attack")) { + const weaponName = roll.label.replace(" attack", ""); + const key = `${roll.character_id}:${weaponName}`; + setCritKeys((prev) => new Set(prev).add(key)); + } + if (roll.character_id && roll.label.includes("damage")) { + const weaponName = roll.label + .replace(" damage", "") + .replace(" (CRIT)", ""); + const key = `${roll.character_id}:${weaponName}`; + setCritKeys((prev) => { + const next = new Set(prev); + next.delete(key); + return next; + }); + } + } + + function handleDiceComplete() { + if (pendingRollRef.current) { + showRollInLog(pendingRollRef.current); + pendingRollRef.current = null; + } + } + // Socket event listeners useEffect(() => { function onCharacterCreated(char: Character) { @@ -162,32 +207,20 @@ export default function CampaignView() { } function onRollResult(roll: RollResult) { - setRolls((prev) => [roll, ...prev].slice(0, 50)); - setFreshIds((prev) => new Set(prev).add(roll.id)); - setTimeout(() => { - setFreshIds((prev) => { - const next = new Set(prev); - next.delete(roll.id); - return next; - }); - }, 2000); - - // Track crits by character+weapon key (e.g. "1:SHORTSWORD") - if (roll.nat20 && roll.character_id && roll.label.includes("attack")) { - const weaponName = roll.label.replace(" attack", ""); - const key = `${roll.character_id}:${weaponName}`; - setCritKeys((prev) => new Set(prev).add(key)); - } - if (roll.character_id && roll.label.includes("damage")) { - const weaponName = roll.label - .replace(" damage", "") - .replace(" (CRIT)", ""); - const key = `${roll.character_id}:${weaponName}`; - setCritKeys((prev) => { - const next = new Set(prev); - next.delete(key); - return next; + // Check if this roll can trigger 3D dice + const hasDice = /\d*d\d+/i.test(roll.dice_expression); + if (hasDice) { + // Queue roll — it will appear in log when dice animation finishes + pendingRollRef.current = roll; + setDiceRoll({ + expression: roll.dice_expression, + rolls: roll.rolls, + characterColor: roll.character_color, + id: roll.id, }); + } else { + // No 3D dice — show immediately + showRollInLog(roll); } } @@ -421,6 +454,7 @@ export default function CampaignView() { )}
+ ); }