- Starting solo game with physics
This commit is contained in:
Kum1ta
2024-08-29 18:43:23 +02:00
parent 24704b8493
commit 64b2e8ab73
33 changed files with 40944 additions and 110 deletions

View File

@ -6,7 +6,7 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/28 12:07:39 by edbernar #+# #+# */
/* Updated: 2024/08/29 00:19:01 by edbernar ### ########.fr */
/* Updated: 2024/08/29 13:58:06 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@ -32,6 +32,7 @@ class SoloGame
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
Ball.create(scene);
Map.create(scene);
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight);
camera.rotation.x = -Math.PI / 2;
@ -39,15 +40,11 @@ class SoloGame
scene.background = new THREE.Color(0x252525);
document.body.appendChild(renderer.domElement);
Players.create(scene);
Ball.create(scene);
controls = new OrbitControls(camera, renderer.domElement);
camera.position.set(0, 20, 0);
// camera.position.set(20, 5, 20);
renderer.setAnimationLoop(loop);
setTimeout(() => {
Ball.moveBall();
}, 1000);
}
static dispose()
@ -78,6 +75,8 @@ function loop()
{
stats.begin();
controls.update();
Ball.update();
Map.update();
Players.update();
renderer.render(scene, camera);
stats.end();

View File

@ -6,7 +6,7 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/28 15:58:03 by edbernar #+# #+# */
/* Updated: 2024/08/29 00:44:26 by edbernar ### ########.fr */
/* Updated: 2024/08/29 13:45:02 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
@ -23,12 +23,10 @@ class Ball
{
static create(scene)
{
ball = createBall();
scene.add(ball);
ball.rotateY(0.8);
ball.rotateY(2.39);
}
static dispose()
@ -36,36 +34,10 @@ class Ball
ball = null;
}
static moveBall()
static update()
{
createInterval();
}
static stopBall()
{
if (interval)
clearInterval(interval);
}
}
function createInterval()
{
interval = setInterval(() => {
console.log(ball.position);
moveForward();
bounceWallTop();
bounceWallTBottom();
bouncePlayer1();
}, 16);
}
function moveForward()
{
const direction = new THREE.Vector3(0, 0, dir);
direction.applyQuaternion(ball.quaternion);
ball.position.add(direction.multiplyScalar(speed));
}
function createBall()
@ -81,55 +53,4 @@ function createBall()
return (mesh);
}
function bounceWallTop()
{
const origin = new THREE.Vector3(ball.position.x, ball.position.y, ball.position.z);
const direction = new THREE.Vector3(ball.position.x, ball.position.y, ball.position.z - 1);
direction.normalize();
const raycaster = new THREE.Raycaster(origin, direction);
const objects = [ wallTop ];
const intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0)
{
if (intersects[0].distance <= 0.5)
ball.rotation.y = Math.PI - ball.rotation.y
}
}
function bounceWallTBottom()
{
const origin = new THREE.Vector3(ball.position.x, ball.position.y, ball.position.z);
const direction = new THREE.Vector3(ball.position.x, ball.position.y, ball.position.z + 1);
direction.normalize();
const raycaster = new THREE.Raycaster(origin, direction);
const objects = [ wallBottom ];
const intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0)
{
if (intersects[0].distance <= 0.4)
ball.rotation.y = Math.PI - ball.rotation.y;
}
}
function bouncePlayer1()
{
const origin = new THREE.Vector3(ball.position.x, ball.position.y, ball.position.z);
const direction = new THREE.Vector3(ball.position.x - 1, ball.position.y, ball.position.z);
direction.normalize();
const raycaster = new THREE.Raycaster(origin, direction);
const objects = [ player1 ];
const intersects = raycaster.intersectObjects(objects);
if (intersects.length > 0)
{
if (intersects[0].distance <= 0.4)
ball.rotation.y = Math.PI - ball.rotation.y;
}
}
export { Ball };
export { Ball, ball };

View File

@ -6,23 +6,35 @@
/* By: edbernar <edbernar@student.42angouleme. +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/08/28 12:23:48 by edbernar #+# #+# */
/* Updated: 2024/08/28 17:01:17 by edbernar ### ########.fr */
/* Updated: 2024/08/29 18:42:55 by edbernar ### ########.fr */
/* */
/* ************************************************************************** */
import * as CANNON from 'cannon-es';
import * as THREE from 'three';
import { ball } from './Ball.js'
const width = 25;
const height = 12.5;
let ground = null;
let spotLight = null;
let wallTop = null;
let wallBottom = null;
let world = null;
const timeStep = 1 / 60;
let groundBody = null;
let wallTopBody = null;
let wallBottomBody = null;
let ballBody = null;
class Map
{
static create(scene)
{
createGround(scene);
world = new CANNON.World({
gravity: new CANNON.Vec3(0, -9.81, 0),
});
ground = createGround(scene);
wallBottom = createWall(false);
wallTop = createWall(true);
spotLight = new THREE.SpotLight({color: 0xffffff});
@ -33,6 +45,33 @@ class Map
scene.add(wallTop);
scene.add(wallBottom);
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
wallTopBody = new CANNON.Body({
shape: new CANNON.Box(new CANNON.Vec3(width, 0.7, 0.2)),
type: CANNON.Body.STATIC,
})
wallTopBody.position.z = -6.15;
wallTopBody.position.y += 0.35;
world.addBody(wallTopBody);
wallBottomBody = new CANNON.Body({
shape: new CANNON.Box(new CANNON.Vec3(width, 0.7, 0.2)),
type: CANNON.Body.STATIC,
})
wallBottomBody.position.z = 6.15;
wallBottomBody.position.y += 0.35;
world.addBody(wallBottomBody);
groundBody = new CANNON.Body({
shape: new CANNON.Plane(),
type: CANNON.Body.STATIC,
});
groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0);
world.addBody(groundBody);
ballBody = new CANNON.Body({
shape: new CANNON.Sphere(0.3),
mass: 1
});
ballBody.position.set(0, 2, 0);
ballBody.velocity.set(0, 0, 0);
world.addBody(ballBody);
}
static dispose()
@ -41,6 +80,19 @@ class Map
spotLight.dispose();
spotLight = null;
}
static update()
{
world.step(timeStep);
ground.position.copy(groundBody.position);
ground.quaternion.copy(groundBody.quaternion);
ball.position.copy(ballBody.position);
ball.quaternion.copy(ballBody.quaternion);
wallBottom.position.copy(wallBottomBody.position);
wallBottom.quaternion.copy(wallBottomBody.quaternion);
wallTop.position.copy(wallTopBody.position);
wallTop.quaternion.copy(wallTopBody.quaternion);
}
}
function createGround(scene)
@ -52,6 +104,7 @@ function createGround(scene)
mesh.rotateX(-Math.PI / 2);
mesh.position.set(0, 0, 0);
scene.add(mesh);
return (mesh);
}
function createWall(onTop)
@ -60,11 +113,11 @@ function createWall(onTop)
const material = new THREE.MeshPhysicalMaterial({color: 0x333333});
const mesh = new THREE.Mesh(geometry, material);
if (onTop)
mesh.position.z = -6.15;
else
mesh.position.z = 6.15;
mesh.position.y += 0.35;
// if (onTop)
// mesh.position.z = -6.15;
// else
// mesh.position.z = 6.15;
// mesh.position.y += 0.35;
return (mesh);
}

1
site/real_game/node_modules/.bin/stats generated vendored Symbolic link
View File

@ -0,0 +1 @@
../stats/bin/stats

View File

@ -1,37 +1,43 @@
{
"hash": "aeb97021",
"configHash": "0b4c6e74",
"lockfileHash": "cd36b699",
"browserHash": "19562a0a",
"hash": "9cbfc9bc",
"configHash": "4027b9ee",
"lockfileHash": "89d910af",
"browserHash": "2df4664b",
"optimized": {
"cannon-es": {
"src": "../../cannon-es/dist/cannon-es.js",
"file": "cannon-es.js",
"fileHash": "e7d2d088",
"needsInterop": false
},
"stats.js": {
"src": "../../stats.js/build/stats.min.js",
"file": "stats__js.js",
"fileHash": "02cf6dab",
"fileHash": "e6b91a0e",
"needsInterop": true
},
"three": {
"src": "../../three/build/three.module.js",
"file": "three.js",
"fileHash": "b84c2f0c",
"fileHash": "694e9996",
"needsInterop": false
},
"three/addons/loaders/GLTFLoader.js": {
"src": "../../three/examples/jsm/loaders/GLTFLoader.js",
"file": "three_addons_loaders_GLTFLoader__js.js",
"fileHash": "c571cff0",
"fileHash": "7920c7d2",
"needsInterop": false
},
"three/examples/jsm/Addons.js": {
"src": "../../three/examples/jsm/Addons.js",
"file": "three_examples_jsm_Addons__js.js",
"fileHash": "b1ac92b5",
"fileHash": "3ac10f53",
"needsInterop": false
},
"three/examples/jsm/controls/OrbitControls.js": {
"src": "../../three/examples/jsm/controls/OrbitControls.js",
"file": "three_examples_jsm_controls_OrbitControls__js.js",
"fileHash": "470fb7a7",
"fileHash": "786c8359",
"needsInterop": false
}
},

10010
site/real_game/node_modules/.vite/deps/cannon-es.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

22
site/real_game/node_modules/cannon-es/LICENSE generated vendored Normal file
View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2015 cannon.js Authors
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

File diff suppressed because it is too large Load Diff

1603
site/real_game/node_modules/cannon-es/dist/cannon-es.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

13023
site/real_game/node_modules/cannon-es/dist/cannon-es.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

70
site/real_game/node_modules/cannon-es/package.json generated vendored Normal file
View File

@ -0,0 +1,70 @@
{
"name": "cannon-es",
"version": "0.20.0",
"license": "MIT",
"description": "A lightweight 3D physics engine written in JavaScript.",
"homepage": "https://github.com/schteppe/cannon.js",
"author": "Stefan Hedman <schteppe@gmail.com> (http://steffe.se)",
"contributors": [
"Cody Persinger <codypersinger@gmail.com> (https://github.com/codynova)",
"Marco Fugaro <marco.fugaro@gmail.com> (https://github.com/marcofugaro)"
],
"keywords": [
"cannon.js",
"cannon",
"physics",
"engine",
"3d"
],
"main": "./dist/cannon-es.cjs.js",
"module": "./dist/cannon-es.js",
"react-native": "./dist/cannon-es.js",
"types": "./dist/cannon-es.d.ts",
"sideEffects": false,
"files": [
"dist/"
],
"scripts": {
"prepare": "husky install",
"start": "npx serve",
"prebuild": "rimraf dist",
"build": "npm run typegen && rollup -c",
"prepublishOnly": "npm run build && npm run test",
"typecheck": "tsc --noEmit --emitDeclarationOnly false --strict",
"typegen": "tsc --outFile dist/cannon-es.d.ts",
"generate-docs": "typedoc",
"test": "jest"
},
"repository": {
"type": "git",
"url": "https://github.com/pmndrs/cannon-es.git"
},
"bugs": {
"url": "https://github.com/pmndrs/cannon-es/issues"
},
"devDependencies": {
"@babel/core": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"@babel/preset-typescript": "^7.16.5",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.1.1",
"@rollup/plugin-replace": "^3.0.0",
"@types/jest": "^27.0.3",
"@types/node": "^17.0.4",
"husky": "^7.0.4",
"jest": "^27.4.5",
"lint-staged": "^12.1.4",
"prettier": "^2.5.1",
"rimraf": "^3.0.2",
"rollup": "^2.62.0",
"rollup-plugin-filesize": "^9.1.1",
"ts-jest": "^27.1.2",
"ts-node": "^10.4.0",
"typedoc": "^0.22.10",
"typescript": "^4.5.4"
},
"lint-staged": {
"*.{js,json,jsx,ts,tsx,md,yaml,yml}": "prettier --write"
}
}

64
site/real_game/node_modules/cannon-es/readme.md generated vendored Normal file
View File

@ -0,0 +1,64 @@
# cannon-es
This is a maintained fork of [cannon.js](https://github.com/schteppe/cannon.js), originally created by Stefan Hedman [@schteppe](https://github.com/schteppe).
It's a type-safe flatbundle (esm and cjs) which allows for **tree shaking** and usage in modern environments.
These minor changes and improvements were also made:
- These PRs from the original repo were merged: [schteppe/cannon.js#433](https://github.com/schteppe/cannon.js/pull/433), [schteppe/cannon.js#430](https://github.com/schteppe/cannon.js/pull/430), [schteppe/cannon.js#418](https://github.com/schteppe/cannon.js/pull/418), [schteppe/cannon.js#360](https://github.com/schteppe/cannon.js/pull/360), [schteppe/cannon.js#265](https://github.com/schteppe/cannon.js/pull/265), [schteppe/cannon.js#392](https://github.com/schteppe/cannon.js/pull/392), [schteppe/cannon.js#424](https://github.com/schteppe/cannon.js/pull/424)
- The `ConvexPolyhedron` constructor now accepts an object instead of a list of arguments. [#6](https://github.com/pmndrs/cannon-es/pull/6)
- The `Cylinder` is now oriented on the Y axis. [#30](https://github.com/pmndrs/cannon-es/pull/30)
- The `type` property of the `Cylinder` is now equal to `Shape.types.CYLINDER`. [#59](https://github.com/pmndrs/cannon-es/pull/59)
- `Body.applyImpulse()` and `Body.applyForce()` are now relative to the center of the body instead of the center of the world [86b0444](https://github.com/schteppe/cannon.js/commit/86b0444c93356aeaa25dd1af795fa162574c6f4b)
- Sleeping bodies now wake up if a force or an impulse is applied to them [#61](https://github.com/pmndrs/cannon-es/pull/61)
- Added a property `World.hasActiveBodies: boolean` which will be false when all physics bodies are sleeping. This allows for invalidating frames when physics aren't active for increased performance.
- Add support for [Trigger bodies](https://pmndrs.github.io/cannon-es/examples/trigger). [#83](https://github.com/pmndrs/cannon-es/pull/83)
- Deprecated properties and methods have been removed.
- The [original cannon.js debugger](https://github.com/schteppe/cannon.js/blob/master/tools/threejs/CannonDebugRenderer.js), which shows the wireframes of each body, has been moved to its own repo [cannon-es-debugger](https://github.com/pmndrs/cannon-es-debugger).
- Added optional property `World.frictionGravity: Vec3` which can be set to customize the force used when computing the friction between two colliding bodies. If `undefined`, `World.gravity` will be used. This property is useful to enable friction in zero gravity. This addresses issue [#224](https://github.com/schteppe/cannon.js/issues/224) and follows the [pattern established for p2.js](https://github.com/schteppe/p2.js/blob/master/src/world/World.js#L88-L92).
If instead you're using three.js in a **React** environment with [react-three-fiber](https://github.com/pmndrs/react-three-fiber), check out [use-cannon](https://github.com/pmndrs/use-cannon)! It's a wrapper around cannon-es.
## Installation
```
yarn add cannon-es
```
## Usage
```js
import { World } from 'cannon-es'
// ...
```
or, if you're using webpack, you can import it like this while still taking advantage of tree shaking:
```js
import * as CANNON from 'cannon-es'
// ...
```
## [Documentation](https://pmndrs.github.io/cannon-es/docs/)
[![](screenshots/docs.png)](https://pmndrs.github.io/cannon-es/docs/)
## [Examples](https://pmndrs.github.io/cannon-es/)
[![](screenshots/examples.png)](https://pmndrs.github.io/cannon-es/)
#### TO DO:
- Fix Octree `as any` assertions, and remove `as any` type assertions wherever possible
- Remove use of defined assertion (!) where possible (profile performance to ensure no degradation)
- Convert to abstract classes where possible (Equation, Solver, etc.?)
- V-HACD support (https://github.com/pmndrs/use-cannon/issues/35#issuecomment-600188994)
- Explore performance enhancements:
- https://github.com/RandyGaul/qu3e
- https://github.com/RandyGaul/cute_headers
- https://github.com/TheRohans/dapao/issues?q=is%3Aissue
- https://github.com/swift502/Sketchbook/commits/master/src/lib/cannon/cannon.js
- https://github.com/schteppe/cannon.js/pulls

4
site/real_game/node_modules/commander/.npmignore generated vendored Normal file
View File

@ -0,0 +1,4 @@
support
test
examples
*.sock

4
site/real_game/node_modules/commander/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.4
- 0.6

107
site/real_game/node_modules/commander/History.md generated vendored Normal file
View File

@ -0,0 +1,107 @@
0.6.1 / 2012-06-01
==================
* Added: append (yes or no) on confirmation
* Added: allow node.js v0.7.x
0.6.0 / 2012-04-10
==================
* Added `.prompt(obj, callback)` support. Closes #49
* Added default support to .choose(). Closes #41
* Fixed the choice example
0.5.1 / 2011-12-20
==================
* Fixed `password()` for recent nodes. Closes #36
0.5.0 / 2011-12-04
==================
* Added sub-command option support [itay]
0.4.3 / 2011-12-04
==================
* Fixed custom help ordering. Closes #32
0.4.2 / 2011-11-24
==================
* Added travis support
* Fixed: line-buffered input automatically trimmed. Closes #31
0.4.1 / 2011-11-18
==================
* Removed listening for "close" on --help
0.4.0 / 2011-11-15
==================
* Added support for `--`. Closes #24
0.3.3 / 2011-11-14
==================
* Fixed: wait for close event when writing help info [Jerry Hamlet]
0.3.2 / 2011-11-01
==================
* Fixed long flag definitions with values [felixge]
0.3.1 / 2011-10-31
==================
* Changed `--version` short flag to `-V` from `-v`
* Changed `.version()` so it's configurable [felixge]
0.3.0 / 2011-10-31
==================
* Added support for long flags only. Closes #18
0.2.1 / 2011-10-24
==================
* "node": ">= 0.4.x < 0.7.0". Closes #20
0.2.0 / 2011-09-26
==================
* Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
0.1.0 / 2011-08-24
==================
* Added support for custom `--help` output
0.0.5 / 2011-08-18
==================
* Changed: when the user enters nothing prompt for password again
* Fixed issue with passwords beginning with numbers [NuckChorris]
0.0.4 / 2011-08-15
==================
* Fixed `Commander#args`
0.0.3 / 2011-08-15
==================
* Added default option value support
0.0.2 / 2011-08-15
==================
* Added mask support to `Command#password(str[, mask], fn)`
* Added `Command#password(str, fn)`
0.0.1 / 2010-01-03
==================
* Initial release

7
site/real_game/node_modules/commander/Makefile generated vendored Normal file
View File

@ -0,0 +1,7 @@
TESTS = $(shell find test/test.*.js)
test:
@./test/run $(TESTS)
.PHONY: test

262
site/real_game/node_modules/commander/Readme.md generated vendored Normal file
View File

@ -0,0 +1,262 @@
# Commander.js
The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).
[![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)
## Installation
$ npm install commander
## Option parsing
Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('commander');
program
.version('0.0.1')
.option('-p, --peppers', 'Add peppers')
.option('-P, --pineapple', 'Add pineapple')
.option('-b, --bbq', 'Add bbq sauce')
.option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
.parse(process.argv);
console.log('you ordered a pizza with:');
if (program.peppers) console.log(' - peppers');
if (program.pineapple) console.log(' - pineappe');
if (program.bbq) console.log(' - bbq');
console.log(' - %s cheese', program.cheese);
```
Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
## Automated --help
The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
```
$ ./examples/pizza --help
Usage: pizza [options]
Options:
-V, --version output the version number
-p, --peppers Add peppers
-P, --pineapple Add pineappe
-b, --bbq Add bbq sauce
-c, --cheese <type> Add the specified type of cheese [marble]
-h, --help output usage information
```
## Coercion
```js
function range(val) {
return val.split('..').map(Number);
}
function list(val) {
return val.split(',');
}
program
.version('0.0.1')
.usage('[options] <file ...>')
.option('-i, --integer <n>', 'An integer argument', parseInt)
.option('-f, --float <n>', 'A float argument', parseFloat)
.option('-r, --range <a>..<b>', 'A range', range)
.option('-l, --list <items>', 'A list', list)
.option('-o, --optional [value]', 'An optional value')
.parse(process.argv);
console.log(' int: %j', program.integer);
console.log(' float: %j', program.float);
console.log(' optional: %j', program.optional);
program.range = program.range || [];
console.log(' range: %j..%j', program.range[0], program.range[1]);
console.log(' list: %j', program.list);
console.log(' args: %j', program.args);
```
## Custom help
You can display arbitrary `-h, --help` information
by listening for "--help". Commander will automatically
exit once you are done so that the remainder of your program
does not execute causing undesired behaviours, for example
in the following executable "stuff" will not output when
`--help` is used.
```js
#!/usr/bin/env node
/**
* Module dependencies.
*/
var program = require('../');
function list(val) {
return val.split(',').map(Number);
}
program
.version('0.0.1')
.option('-f, --foo', 'enable some foo')
.option('-b, --bar', 'enable some bar')
.option('-B, --baz', 'enable some baz');
// must be before .parse() since
// node's emit() is immediate
program.on('--help', function(){
console.log(' Examples:');
console.log('');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
console.log('');
});
program.parse(process.argv);
console.log('stuff');
```
yielding the following help output:
```
Usage: custom-help [options]
Options:
-h, --help output usage information
-V, --version output the version number
-f, --foo enable some foo
-b, --bar enable some bar
-B, --baz enable some baz
Examples:
$ custom-help --help
$ custom-help -h
```
## .prompt(msg, fn)
Single-line prompt:
```js
program.prompt('name: ', function(name){
console.log('hi %s', name);
});
```
Multi-line prompt:
```js
program.prompt('description:', function(name){
console.log('hi %s', name);
});
```
Coercion:
```js
program.prompt('Age: ', Number, function(age){
console.log('age: %j', age);
});
```
```js
program.prompt('Birthdate: ', Date, function(date){
console.log('date: %s', date);
});
```
## .password(msg[, mask], fn)
Prompt for password without echoing:
```js
program.password('Password: ', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
Prompt for password with mask char "*":
```js
program.password('Password: ', '*', function(pass){
console.log('got "%s"', pass);
process.stdin.destroy();
});
```
## .confirm(msg, fn)
Confirm with the given `msg`:
```js
program.confirm('continue? ', function(ok){
console.log(' got %j', ok);
});
```
## .choose(list, fn)
Let the user choose from a `list`:
```js
var list = ['tobi', 'loki', 'jane', 'manny', 'luna'];
console.log('Choose the coolest pet:');
program.choose(list, function(i){
console.log('you chose %d "%s"', i, list[i]);
});
```
## Links
- [API documentation](http://visionmedia.github.com/commander.js/)
- [ascii tables](https://github.com/LearnBoost/cli-table)
- [progress bars](https://github.com/visionmedia/node-progress)
- [more progress bars](https://github.com/substack/node-multimeter)
- [examples](https://github.com/visionmedia/commander.js/tree/master/examples)
## License
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2
site/real_game/node_modules/commander/index.js generated vendored Normal file
View File

@ -0,0 +1,2 @@
module.exports = require('./lib/commander');

1026
site/real_game/node_modules/commander/lib/commander.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

13
site/real_game/node_modules/commander/package.json generated vendored Normal file
View File

@ -0,0 +1,13 @@
{
"name": "commander"
, "version": "0.5.2"
, "description": "the complete solution for node.js command-line programs"
, "keywords": ["command", "option", "parser", "prompt", "stdin"]
, "author": "TJ Holowaychuk <tj@vision-media.ca>"
, "repository": { "type": "git", "url": "https://github.com/visionmedia/commander.js.git" }
, "dependencies": {}
, "devDependencies": { "should": ">= 0.0.1" }
, "scripts": { "test": "make test" }
, "main": "index"
, "engines": { "node": ">= 0.4.x" }
}

21
site/real_game/node_modules/stats-js/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2009-2016 stats.js authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

51
site/real_game/node_modules/stats-js/README.md generated vendored Normal file
View File

@ -0,0 +1,51 @@
stats.js
========
#### JavaScript Performance Monitor ####
This class provides a simple info box that will help you monitor your code performance.
* **FPS** Frames rendered in the last second. The higher the number the better.
* **MS** Milliseconds needed to render a frame. The lower the number the better.
* **MB** MBytes of allocated memory. (Run Chrome with `--enable-precise-memory-info`)
* **CUSTOM** User-defined panel support.
### Screenshots ###
![fps.png](https://raw.githubusercontent.com/Kevnz/stats.js/master/files/fps.png)
![ms.png](https://raw.githubusercontent.com/Kevnz/stats.js/master/files/ms.png)
![mb.png](https://raw.githubusercontent.com/Kevnz/stats.js/master/files/mb.png)
![custom.png](https://raw.githubusercontent.com/Kevnz/stats.js/master/files/custom.png)
### Usage ###
```javascript
var stats = new Stats();
stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );
function animate() {
stats.begin();
// monitored code goes here
stats.end();
requestAnimationFrame( animate );
}
requestAnimationFrame( animate );
```
### Bookmarklet ###
You can add this code to any page using the following bookmarklet:
```javascript
javascript:(function(){var script=document.createElement('script');script.onload=function(){var stats=new Stats();document.body.appendChild(stats.dom);requestAnimationFrame(function loop(){stats.update();requestAnimationFrame(loop)});};script.src='//cdn.jsdelivr.net/gh/Kevnz/stats.js/build/stats.min.js';document.head.appendChild(script);})()
```

179
site/real_game/node_modules/stats-js/build/stats.js generated vendored Normal file
View File

@ -0,0 +1,179 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Stats = factory());
}(this, (function () { 'use strict';
/**
* @author mrdoob / http://mrdoob.com/
*/
var Stats = function () {
var mode = 0;
var container = document.createElement( 'div' );
container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:90000';
container.addEventListener( 'click', function ( event ) {
event.preventDefault();
showPanel( ++ mode % container.children.length );
}, false );
//
function addPanel( panel ) {
container.appendChild( panel.dom );
return panel;
}
function showPanel( id ) {
for ( var i = 0; i < container.children.length; i ++ ) {
container.children[ i ].style.display = i === id ? 'block' : 'none';
}
mode = id;
}
//
var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0;
var fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) );
var msPanel = addPanel( new Stats.Panel( 'MS', '#0f0', '#020' ) );
if ( self.performance && self.performance.memory ) {
var memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) );
}
showPanel( 0 );
return {
REVISION: 16,
dom: container,
addPanel: addPanel,
showPanel: showPanel,
begin: function () {
beginTime = ( performance || Date ).now();
},
end: function () {
frames ++;
var time = ( performance || Date ).now();
msPanel.update( time - beginTime, 200 );
if ( time >= prevTime + 1000 ) {
fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 );
prevTime = time;
frames = 0;
if ( memPanel ) {
var memory = performance.memory;
memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 );
}
}
return time;
},
update: function () {
beginTime = this.end();
},
// Backwards Compatibility
domElement: container,
setMode: showPanel
};
};
Stats.Panel = function ( name, fg, bg ) {
var min = Infinity, max = 0, round = Math.round;
var PR = round( window.devicePixelRatio || 1 );
var WIDTH = 80 * PR, HEIGHT = 48 * PR,
TEXT_X = 3 * PR, TEXT_Y = 2 * PR,
GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR,
GRAPH_WIDTH = 74 * PR, GRAPH_HEIGHT = 30 * PR;
var canvas = document.createElement( 'canvas' );
canvas.width = WIDTH;
canvas.height = HEIGHT;
canvas.style.cssText = 'width:80px;height:48px';
var context = canvas.getContext( '2d' );
context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif';
context.textBaseline = 'top';
context.fillStyle = bg;
context.fillRect( 0, 0, WIDTH, HEIGHT );
context.fillStyle = fg;
context.fillText( name, TEXT_X, TEXT_Y );
context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
return {
dom: canvas,
update: function ( value, maxValue ) {
min = Math.min( min, value );
max = Math.max( max, value );
context.fillStyle = bg;
context.globalAlpha = 1;
context.fillRect( 0, 0, WIDTH, GRAPH_Y );
context.fillStyle = fg;
context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y );
context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT );
context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT );
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) );
}
};
};
return Stats;
})));

View File

@ -0,0 +1 @@
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Stats=t()}(this,function(){"use strict";var c=function(){var n=0,l=document.createElement("div");function e(e){return l.appendChild(e.dom),e}function t(e){for(var t=0;t<l.children.length;t++)l.children[t].style.display=t===e?"block":"none";n=e}l.style.cssText="position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000",l.addEventListener("click",function(e){e.preventDefault(),t(++n%l.children.length)},!1);var i=(performance||Date).now(),a=i,o=0,f=e(new c.Panel("FPS","#0ff","#002")),r=e(new c.Panel("MS","#0f0","#020"));if(self.performance&&self.performance.memory)var d=e(new c.Panel("MB","#f08","#201"));return t(0),{REVISION:16,dom:l,addPanel:e,showPanel:t,begin:function(){i=(performance||Date).now()},end:function(){o++;var e=(performance||Date).now();if(r.update(e-i,200),a+1e3<=e&&(f.update(1e3*o/(e-a),100),a=e,o=0,d)){var t=performance.memory;d.update(t.usedJSHeapSize/1048576,t.jsHeapSizeLimit/1048576)}return e},update:function(){i=this.end()},domElement:l,setMode:t}};return c.Panel=function(n,l,i){var a=1/0,o=0,f=Math.round,r=f(window.devicePixelRatio||1),d=80*r,e=48*r,c=3*r,p=2*r,u=3*r,s=15*r,m=74*r,h=30*r,y=document.createElement("canvas");y.width=d,y.height=e,y.style.cssText="width:80px;height:48px";var v=y.getContext("2d");return v.font="bold "+9*r+"px Helvetica,Arial,sans-serif",v.textBaseline="top",v.fillStyle=i,v.fillRect(0,0,d,e),v.fillStyle=l,v.fillText(n,c,p),v.fillRect(u,s,m,h),v.fillStyle=i,v.globalAlpha=.9,v.fillRect(u,s,m,h),{dom:y,update:function(e,t){a=Math.min(a,e),o=Math.max(o,e),v.fillStyle=i,v.globalAlpha=1,v.fillRect(0,0,d,s),v.fillStyle=l,v.fillText(f(e)+" "+n+" ("+f(a)+"-"+f(o)+")",c,p),v.drawImage(y,u+r,s,m-r,h,u,s,m-r,h),v.fillRect(u+m-r,s,r,h),v.fillStyle=i,v.globalAlpha=.9,v.fillRect(u+m-r,s,r,f((1-e/t)*h))}}},c});

38
site/real_game/node_modules/stats-js/package.json generated vendored Normal file
View File

@ -0,0 +1,38 @@
{
"name": "stats-js",
"version": "1.0.1",
"description": "JavaScript Performance Monitor",
"main": "build/stats.min.js",
"directories": {
"example": "examples"
},
"repository": {
"type": "git",
"url": "git://github.com/Kevnz/stats.js.git"
},
"keywords": [
"stats",
"webgl"
],
"author": "Kevin Isom <kevin.isom@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/Kevnz/stats.js/issues"
},
"homepage": "https://github.com/Kevnz/stats.js",
"files": [
"build",
"src"
],
"scripts": {
"build": "rollup -c",
"build-uglify": "rollup -c && uglifyjs build/stats.js -cm --preamble \"// stats.js - http://github.com/kevnz/stats.js\" > build/stats.min.js",
"build-closure": "rollup -c && java -jar utils/compiler/closure-compiler-v20160713.jar --language_in=ECMASCRIPT5_STRICT --js build/stats.js --js_output_file build/stats.min.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"rollup": "^0.36.0",
"uglify-js": "^3.4.9",
"uglifyjs": "^2.4.10"
}
}

171
site/real_game/node_modules/stats-js/src/Stats.js generated vendored Normal file
View File

@ -0,0 +1,171 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
var Stats = function () {
var mode = 0;
var container = document.createElement( 'div' );
container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:90000';
container.addEventListener( 'click', function ( event ) {
event.preventDefault();
showPanel( ++ mode % container.children.length );
}, false );
//
function addPanel( panel ) {
container.appendChild( panel.dom );
return panel;
}
function showPanel( id ) {
for ( var i = 0; i < container.children.length; i ++ ) {
container.children[ i ].style.display = i === id ? 'block' : 'none';
}
mode = id;
}
//
var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0;
var fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) );
var msPanel = addPanel( new Stats.Panel( 'MS', '#0f0', '#020' ) );
if ( self.performance && self.performance.memory ) {
var memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) );
}
showPanel( 0 );
return {
REVISION: 16,
dom: container,
addPanel: addPanel,
showPanel: showPanel,
begin: function () {
beginTime = ( performance || Date ).now();
},
end: function () {
frames ++;
var time = ( performance || Date ).now();
msPanel.update( time - beginTime, 200 );
if ( time >= prevTime + 1000 ) {
fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 );
prevTime = time;
frames = 0;
if ( memPanel ) {
var memory = performance.memory;
memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 );
}
}
return time;
},
update: function () {
beginTime = this.end();
},
// Backwards Compatibility
domElement: container,
setMode: showPanel
};
};
Stats.Panel = function ( name, fg, bg ) {
var min = Infinity, max = 0, round = Math.round;
var PR = round( window.devicePixelRatio || 1 );
var WIDTH = 80 * PR, HEIGHT = 48 * PR,
TEXT_X = 3 * PR, TEXT_Y = 2 * PR,
GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR,
GRAPH_WIDTH = 74 * PR, GRAPH_HEIGHT = 30 * PR;
var canvas = document.createElement( 'canvas' );
canvas.width = WIDTH;
canvas.height = HEIGHT;
canvas.style.cssText = 'width:80px;height:48px';
var context = canvas.getContext( '2d' );
context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif';
context.textBaseline = 'top';
context.fillStyle = bg;
context.fillRect( 0, 0, WIDTH, HEIGHT );
context.fillStyle = fg;
context.fillText( name, TEXT_X, TEXT_Y );
context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
return {
dom: canvas,
update: function ( value, maxValue ) {
min = Math.min( min, value );
max = Math.max( max, value );
context.fillStyle = bg;
context.globalAlpha = 1;
context.fillRect( 0, 0, WIDTH, GRAPH_Y );
context.fillStyle = fg;
context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y );
context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT );
context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT );
context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) );
}
};
};
export { Stats as default };

7
site/real_game/node_modules/statsjs/LICENSE generated vendored Normal file
View File

@ -0,0 +1,7 @@
Copyright (c) 2012 Angus Gibbs
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

32
site/real_game/node_modules/statsjs/README.md generated vendored Normal file
View File

@ -0,0 +1,32 @@
# Stats.js by [Angus Gibbs](http://angusgibbs.com)
Provides functions for many of the statistical operations that you might need.
## About
Stats.js currently supports many of the statistical functions that you might need, including
* regression lines (linear, power, exponential)
* min, max, mean, median, first quartile, third quartile
* least common multiple and greatest common factor
* standard deviation
* sorting a list of points by an attribute
* probabilities (binomial, geometric, normal)
* z procedures
It also supports many of the functions on the data set that you'd expect from [Underscore](http://underscore.js), such as `pluck`, `map`, and `each`.
See the [getting started guide](https://github.com/angusgibbs/statsjs/blob/master/docs/getting_started.md) for more information.
## Roadmap
* Better documentation
* Auto-detect best regression line
## Contributing
Patches are welcome, just make sure there are matching unit tests. Tests use [mocha](http://visionmedia.github.com/mocha/) with my fork of [expect.js](https://github.com/angusgibbs/expect.js) (which allows you to assert that a value is within a certain error range of another value). Once you clone the repo (either your fork or this repository), `cd` into it and run `npm install` to install mocha and expect.js. Tests can be found within `test/test.js`.
## License
Stats.js is licensed under the [MIT License](http://opensource.org/licenses/mit-license.php). See https://github.com/angusgibbs/statsjs/blob/master/LICENSE for the full license.

954
site/real_game/node_modules/statsjs/lib/stats.js generated vendored Normal file
View File

@ -0,0 +1,954 @@
/*!
* Stats.js (https://github.com/angusgibbs/stats.js)
* Copyright 2012 Angus Gibbs
*/
(function(root) {
// Create the top level stats object
// =================================
// Wrapper to create a chainable stats object.
//
// arr - The array to work with.
//
// Returns a new chainable object.
var stats = function(arr) {
return new stats.init(arguments.length > 1 ?
Array.prototype.slice.call(arguments, 0) :
arr);
};
// Creates a new chainable array object.
//
// arr - The array to work with.
//
// Returns a new chainable object.
stats.init = function(arr) {
this.arr = arr;
this.length = arr.length;
};
// Define the methods for the stats object
stats.init.prototype = {
// Calls a function on each element in an array or JSON object.
//
// fn - The function to call on each element.
// el - The array or object element
// index - The index or key of the array element
// arr - The array or object
//
// Returns nothing.
each: function(fn) {
if (this.arr.length === undefined) {
// The wrapped array is a JSON object
for (var key in arr) {
fn.call(this.arr[key], key, this.arr[key], this.arr);
}
} else {
// The wrapper array is an array
for (var i = 0, l = this.arr.length; i < l; i++) {
fn.call(this.arr[i], this.arr[i], i, this.arr);
}
}
return this;
},
// Replaces each element in an array or JSON object with the result of
// the function that is called against each element.
//
// fn - The function to call on each element
// el - The array or object element
// index - The index or key of the array element
//
// Returns nothing.
map: function(fn) {
var arr = this.arr;
if (arr.length === undefined) {
// The wrapped array is a JSON object
for (var key in arr) {
this.arr[key] = fn.call(arr[key], arr[key], key, arr);
}
} else {
// The wrapped array is an array
for (var i = 0, l = this.arr.length; i < l; i++) {
this.arr[i] = fn.call(arr[i], arr[i], i, arr);
}
}
return this;
},
// Replaces each element of the array with the attribute of that given
// element.
//
// attr - The attribute to pluck.
//
// Returns nothing.
pluck: function(attr) {
var newArr = [];
if (this.arr.length === undefined) {
// The wrapped array is a JSON object
for (var key in arr) {
newArr.push(this.arr[key][attr]);
}
} else {
// The wrapped array is an array
for (var i = 0, l = this.arr.length; i < l; i++) {
newArr.push(this.arr[i][attr]);
}
}
return stats(newArr);
},
// Finds the smallest number.
//
// attr - Optional. If passed, the elemnt with the minimum value for the
// given attribute will be returned.
//
// Returns the minimum.
min: function(attr) {
// Get the numbers
var arr = this.arr;
// Go through each of the numbers and find the minimum
var minimum = attr == null ? arr[0] : arr[0][attr];
var minimumEl = attr == null ? arr[0] : arr[0];
stats(arr).each(function(num, index) {
if ((attr == null ? num : num[attr]) < minimum) {
minimum = attr == null ? num : num[attr];
minimumEl = num;
}
});
return minimumEl;
},
// Finds the largest number.
//
// attr - Optional. If passed, the elemnt with the maximum value for the
// given attribute will be returned.
//
// Returns the maximum.
max: function(attr) {
// Get the numbers
var arr = this.arr;
// Go through each of the numbers and find the maximum
var maximum = attr == null ? arr[0] : arr[0][attr];
var maximumEl = attr == null ? arr[0] : arr[0];
stats(arr).each(function(num, index) {
if ((attr == null ? num : num[attr]) > maximum) {
maximum = attr == null ? num : num[attr];
maximumEl = num;
}
});
return maximumEl;
},
// Finds the median of the numbers.
//
// Returns the median.
median: function() {
// Sort the numbers
var arr = this.clone().sort().toArray();
if (arr.length % 2 === 0) {
// There are an even number of elements in the array; the median
// is the average of the middle two
return (arr[arr.length / 2 - 1] + arr[arr.length / 2]) / 2;
} else {
// There are an odd number of elements in the array; the median
// is the middle one
return arr[(arr.length - 1) / 2];
}
},
// Finds the first quartile of the numbers.
//
// Returns the first quartile.
q1: function() {
// Handle the single element case
if (this.length == 1) {
return this.arr[0];
}
// Sort the numbers
var nums = this.clone().sort();
// The first quartile is the median of the lower half of the numbers
return nums.slice(0, Math.floor(nums.size() / 2)).median();
},
// Finds the third quartile of the numbers.
//
// Returns the third quartile.
q3: function() {
// Handle the single element case
if (this.length == 1) {
return this.arr[0];
}
// Sort the numbers
var nums = this.clone().sort();
// The third quartile is the median of the upper half of the numbers
return nums.slice(Math.ceil(nums.size() / 2)).median();
},
// Finds the interquartile range of the data set.
//
// Returns the IQR.
iqr: function() {
return this.q3() - this.q1();
},
// Finds all outliers in the data set, using the 1.5 * IQR away from
// the median test.
//
// Returns a new stats object with the outliers.
findOutliers: function() {
// Get the median and the range that the number must fall within
var median = this.median();
var range = this.iqr() * 1.5;
// Create a new stats object to hold the outliers
var outliers = stats([]);
// Go through each element in the data set and test to see if it
// is an outlier
this.each(function(num) {
if (Math.abs(num - median) > range) {
// The number is an outlier
outliers.push(num);
}
});
return outliers;
},
// Tests if the given number would be an outlier in the data set.
//
// num - The number to test.
//
// Returns a boolean.
testOutlier: function(num) {
return (Math.abs(num - this.median()) > this.iqr() * 1.5);
},
// Removes all the outliers from the data set.
//
// Returns nothing.
removeOutliers: function() {
// Get the median and the range that the number must fall within
var median = this.median();
var range = this.iqr() * 1.5;
// Create a new stats object that will hold all the non-outliers
var notOutliers = stats([]);
// Go through each element in the data set and test to see if it
// is an outlier
this.each(function(num) {
if (Math.abs(num - median) <= range) {
// The number is not an outlier
notOutliers.push(num);
}
});
return notOutliers;
},
// Finds the mean of the numbers.
//
// Returns the mean.
mean: function() {
return this.sum() / this.size();
},
// Finds the sum of the numbers.
//
// Returns the sum.
sum: function() {
var result = 0;
this.each(function(num) {
result += num;
});
return result;
},
// Finds the standard deviation of the numbers.
//
// Returns the standard deviation.
stdDev: function() {
// Get the mean
var mean = this.mean();
// Get a new stats object to work with
var nums = this.clone();
// Map each element of nums to the square of the element minus the
// mean
nums.map(function(num) {
return Math.pow(num - mean, 2);
});
// Return the standard deviation
return Math.sqrt(nums.sum() / (nums.size() - 1));
},
// Calculates the correlation coefficient for the data set.
//
// Returns the value of r.
r: function() {
// Get the x and y coordinates
var xCoords = this.pluck('x');
var yCoords = this.pluck('y');
// Get the means for the x and y coordinates
var meanX = xCoords.mean();
var meanY = yCoords.mean();
// Get the standard deviations for the x and y coordinates
var stdDevX = xCoords.stdDev();
var stdDevY = yCoords.stdDev();
// Map each element to the difference of the element and the mean
// divided by the standard deviation
xCoords.map(function(num) {
return (num - meanX) / stdDevX;
});
yCoords.map(function(num) {
return (num - meanY) / stdDevY;
});
// Multiply each element in the x by the corresponding value in
// the y
var nums = this.clone().map(function(num, index) {
return xCoords.get(index) * yCoords.get(index);
});
// r is the sum of xCoords over the number of points minus 1
return nums.sum() / (nums.size() - 1);
},
// Calculates the Least Squares Regression line for the data set.
//
// Returns an object with the slope and y intercept.
linReg: function() {
// Get the x and y coordinates
var xCoords = this.pluck('x');
var yCoords = this.pluck('y');
// Get the means for the x and y coordinates
var meanX = xCoords.mean();
var meanY = yCoords.mean();
// Get the standard deviations for the x and y coordinates
var stdDevX = xCoords.stdDev();
var stdDevY = yCoords.stdDev();
// Calculate the correlation coefficient
var r = this.r();
// Calculate the slope
var slope = r * (stdDevY / stdDevX);
// Calculate the y-intercept
var yIntercept = meanY - slope * meanX;
return {
slope: slope,
yIntercept: yIntercept,
r: r
};
},
// Calculates the exponential regression line for the data set.
//
// Returns an object with the coefficient, base, and correlation
// coefficient for the linearized data.
expReg: function() {
// Get y coordinates
var yCoords = this.pluck('y');
// Do a semi-log transformation of the coordinates
yCoords.map(function(num) {
return Math.log(num);
});
// Get a new stats object to work with that has the transformed data
var nums = this.clone().map(function(coord, index) {
return {
x: coord.x,
y: yCoords.get(index)
};
});
// Calculate the linear regression for the linearized data
var linReg = nums.linReg();
// Calculate the coefficient for the exponential equation
var coefficient = Math.pow(Math.E, linReg.yIntercept);
// Calculate the base for the exponential equation
var base = Math.pow(Math.E, linReg.slope);
return {
coefficient: coefficient,
base: base,
r: linReg.r
};
},
// Calculates the power regression line for the data set.
//
// Returns an object with the coefficient, base, and correlation
// coefficient for the linearized data.
powReg: function() {
// Get y coordinates
var xCoords = this.pluck('x');
var yCoords = this.pluck('y');
// Do a log-log transformation of the coordinates
xCoords.map(function(num) {
return Math.log(num);
});
yCoords.map(function(num) {
return Math.log(num);
});
// Get a new stats object to work with that has the transformed data
var nums = this.clone().map(function(coord, index) {
return {
x: xCoords.get(index),
y: yCoords.get(index)
};
});
// Calculate the linear regression for the linearized data
var linReg = nums.linReg();
// Calculate the coefficient for the power equation
var coefficient = Math.pow(Math.E, linReg.yIntercept);
// Calculate the exponent for the power equation
var exponent = linReg.slope;
return {
coefficient: coefficient,
exponent: exponent,
r: linReg.r
};
},
// Returns the number of elements.
size: function() {
return this.arr.length;
},
// Clones the current stats object, providing a new stats object which
// can be changed without modifying the original object.
//
// Returns a new stats object.
clone: function() {
return stats(this.arr.slice(0));
},
// Sorts the internal array, optionally by an attribute.
//
// attr - The attribute of the JSON object to sort by. (Optional.)
//
// Returns nothing.
sort: function(attr) {
// Create the sort function
var sortFn;
// CASE: Simple ascending sort
if (attr == null) {
sortFn = function(a, b) { return a - b; };
}
// CASE: Simple descending sort
else if (attr === true) {
sortFn = function(a, b) { return b - a; };
}
// CASE: Sort by an attribute
else if (typeof attr === 'string') {
sortFn = function(a, b) { return a[attr] - b[attr]; };
}
// CASE: Sort by a function
else {
sortFn = attr;
}
this.arr = this.arr.sort(sortFn);
return this;
},
// Gets an element from the object.
//
// i - The index to retrieve.
//
// Returns the element at that index.
get: function(i) {
return this.arr[i];
},
// Sets an element on the object.
//
// i - The index to set.
// val - The value to set the index to.
//
// Returns nothing.
set: function(i, val) {
this.arr[i] = val;
return this;
},
// Calculates the greatest common divisor of the set.
//
// Returns a Number, the gcd.
gcd: function() {
// Create a new stats object to work with
var nums = this.clone();
// Go through each element and make the element the gcd of it
// and the element to its left
for (var i = 1; i < nums.size(); i++) {
nums.set(i, gcd(nums.get(i - 1), nums.get(i)));
}
// The gcd of all the numbers is now in the final element
return nums.get(nums.size() - 1);
},
// Calculates the least common multiple of the set.
//
// Returns a Number, the lcm.
lcm: function() {
// Create a new stats object to work with
var nums = this.clone();
// Go through each element and make the element the lcm of it
// and the element to its left
for (var i = 1; i < nums.size(); i++) {
nums.set(i, lcm(nums.get(i - 1), nums.get(i)));
}
// The lcm of all the numbers if now in the final element
return nums.get(nums.size() - 1);
}
};
// Private. Calculates the gcd of two numbers using Euclid's method.
//
// Returns a Number.
function gcd(a, b) {
if (b === 0) {
return a;
}
return gcd(b, a - b * Math.floor(a / b));
}
// Private. Calculates the lcm of two numbers.
//
// Returns a Number.
function lcm(a, b) {
// The least common multiple is the absolute value of the product of
// the numbers divided by the greatest common denominator
return Math.abs(a * b) / gcd(a, b);
}
// Provide built in JavaScript array mutator methods for the data list
var mutators = ['pop', 'push', 'shift', 'splice', 'unshift'];
for (var i = 0; i < mutators.length; i++) {
stats.init.prototype[mutators[i]] = (function(method) {
return function() {
return Array.prototype[method].apply(
this.arr,
Array.prototype.slice.call(arguments, 0)
);
};
})(mutators[i]);
}
// Provide built in JavaScript array accessor methods for the data list
var accessors = ['concat', 'join', 'slice', 'reverse'];
for (var i = 0; i < accessors.length; i++) {
stats.init.prototype[accessors[i]] = (function(method) {
return function() {
this.arr = Array.prototype[method].apply(
this.arr,
Array.prototype.slice.call(arguments, 0)
);
return this;
};
})(accessors[i]);
}
// Override the built-in #toJSON() and #toArray() methods
stats.init.prototype.toJSON = stats.init.prototype.toArray = function() {
return this.arr;
};
// Creates a list from the specified lower bound to the specified upper
// bound.
//
// lower - The lower bound.
// upper - The upper bound.
// step - The amount to count by.
//
// Returns a new stats object.
stats.list = function(lower, upper, step) {
// Create the array
var arr = [];
for (var i = lower; i <= upper; i += step || 1) {
arr[i - lower] = i;
}
return stats(arr);
};
// Computes the factorial of a number.
//
// num - The number.
//
// Returns the factorial.
stats.factorial = function(num) {
// Handle the special case of 0
if (num === 0) {
return 1;
}
// Otherwise compute the factorial
for (var i = num - 1; i > 1; i--) {
num *= i;
}
return num;
};
// Computes a permutation.
//
// n - The length of the set.
// r - The number of elements in the subset.
//
// Returns the permutation.
stats.permutation = stats.nPr = function(n, r) {
return stats.factorial(n) / stats.factorial(n - r);
};
// Computes a combination.
//
// n - The length of the set.
// r - The number of elements in the subset.
//
// Returns the combination.
stats.combination = stats.nCr = function(n, r) {
return stats.factorial(n) /
(stats.factorial(r) * stats.factorial(n - r));
};
// Computes the probability of a binomial event.
//
// trials - The number of trials.
// p - The probability of success.
// x - The event number (optional).
//
// If x is not passed, an array with all the probabilities
// will be returned.
//
// Returns a number or an array.
stats.binompdf = function(trials, p, x) {
// CASE: Specific event was passed
if (x != null) {
// Return 0 if the event does not exist
if (x > trials || x < 0) {
return 0;
}
// Return the probability otherwise
return stats.nCr(trials, x) * Math.pow(p, x) *
Math.pow(1 - p, trials - x);
}
// CASE: No specific event was passed
else {
// Compute the probabilities
return stats.list(0, trials).map(function(num) {
return stats.binompdf(trials, p, num);
}).toArray();
}
};
// Computes the cumulative probability of a binomial event.
//
// trials - The number of trials.
// p - The probability of success.
// x - The upper bound (inclusive).
//
// Returns the probability.
stats.binomcdf = function(trials, p, x) {
return stats.list(0, x).map(function(num) {
return stats.binompdf(trials, p, num);
}).sum();
};
// Computes the probability of a geometric event.
//
// p - The probability of success.
// x - The event number.
//
// Returns the probability.
stats.geompdf = function(p, x) {
return Math.pow(1 - p, x - 1) * p;
};
// Computes the cumulative probability of a geometric event.
//
// p - The probability of success.
// x - The event number.
//
// Returns the probability.
stats.geomcdf = function(p, x) {
return stats.list(1, x).map(function(num) {
return stats.geompdf(p, num);
}).sum();
};
// Computes the normal probability of an event.
//
// x - The event number.
// mu - The mean.
// sigma - The standard deviation.
//
// Returns the probability.
stats.normalpdf = function(x, mu, sigma) {
return (1 / (sigma * Math.sqrt(2 * Math.PI))) *
Math.exp(-1 * (x - mu) * (x - mu) /
(2 * sigma * sigma));
};
// Computes the cumulative normal probability of an event.
//
// x - The event number.
// mu - The mean.
// sigma - The standard deviation.
//
// If four parameters are passed the first two are taken as the
// low and high.
//
// Returns the probability.
stats.normalcdf = function(x, mu, sigma) {
// If four parameters were passed, return the difference of
// the probabilities of the upper and lower
if (arguments.length === 4) {
// The cumulative probability is the difference of the
// probabilities of the upper and the lower
return stats.normalcdf(arguments[1], arguments[2], arguments[3]) -
stats.normalcdf(arguments[0], arguments[2], arguments[3]);
}
// Convert the event to a z score
var z = (x - mu) / sigma;
// The probability will be stored here
var p;
// Coefficients
var p0 = 220.2068679123761;
var p1 = 221.2135961699311;
var p2 = 112.0792914978709;
var p3 = 33.91286607838300;
var p4 = 6.373962203531650;
var p5 = .7003830644436881;
var p6 = .03526249659989109;
var q0 = 440.4137358247522;
var q1 = 793.8265125199484;
var q2 = 637.3336333788311;
var q3 = 296.5642487796737;
var q4 = 86.78073220294608;
var q5 = 16.06417757920695;
var q6 = 1.755667163182642;
var q7 = .08838834764831844;
// Another coefficient (10/sqrt(2))
var cutoff = 7.071;
// Cache the absolute value of the z score
var zabs = Math.abs(z);
// If you're more than 37 z scores away just return 1 or 0
if (z > 37) {
return 1;
}
if (z < -37) {
return 0.0;
}
// Compute the normalpdf of this event
var exp = Math.exp(-.5 * zabs * zabs);
var pdf = exp / Math.sqrt(2 * Math.PI);
// Compute the probability
if (zabs < cutoff) {
p = exp*((((((p6*zabs + p5)*zabs + p4)*zabs + p3)*zabs +
p2)*zabs + p1)*zabs + p0)/(((((((q7*zabs + q6)*zabs +
q5)*zabs + q4)*zabs + q3)*zabs + q2)*zabs + q1)*zabs +
q0);
}
else {
p = pdf/(zabs + 1.0/(zabs + 2.0/(zabs + 3.0/(zabs + 4.0/
(zabs + 0.65)))));
}
if (z < 0.0) {
return p;
} else {
return 1 - p;
}
};
// Computes the inverse normal.
//
// p - The probability of x being less than or equal to *x*, the value we
// are looking for.
//
// Returns the x value.
stats.invNorm = function(p) {
// Coefficients for the rational approximation
var a = [
-3.969683028665376e+01,
2.209460984245205e+02,
-2.759285104469687e+02,
1.383577518672690e+02,
-3.066479806614716e+01,
2.506628277459239e+00
];
var b = [
-5.447609879822406e+01,
1.615858368580409e+02,
-1.556989798598866e+02,
6.680131188771972e+01,
-1.328068155288572e+01
];
var c = [
-7.784894002430293e-03,
-3.223964580411365e-01,
-2.400758277161838e+00,
-2.549732539343734e+00,
4.374664141464968e+00,
2.938163982698783e+00
];
var d = [
7.784695709041462e-03,
3.224671290700398e-01,
2.445134137142996e+00,
3.754408661907416e+00
];
// Breakpoints
var pLow = .02425;
var pHigh = 1 - pLow;
// Rational appoximation for the lower region
if (0 < p && p < pLow) {
var q = Math.sqrt(-2 * Math.log(p));
return (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) /
((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) *q + 1);
}
else if (pLow <= p && p <= pHigh) {
var q = p - 0.5;
var r = q * q;
return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q /
(((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
}
else if (pHigh < p && p < 1) {
var q = Math.sqrt(-2 * Math.log(1 - p));
return -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) /
((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1);
}
};
// Runs a 1-mean z-test.
//
// muZero - The proposed population mean.
// sigma - The standard deviation of the population.
// xBar - The sample mean.
// n - The sample size.
// inequality - One of "notequal", "lessthan", or "greaterthan", depending
// on what you're testing
//
// Returns an object with the z-test statistic (z) and P-value (p).
stats.ZTest = function(muZero, sigma, xBar, n, inequality) {
// Calculate the z-test statistic
var z = (xBar - muZero) / (sigma / Math.sqrt(n));
// Calculate the P-value
var p;
if (z < 0) {
// Use normalcdf from -infinity to the z statistic
p = stats.normalcdf(-Infinity, z, 0, 1);
}
else {
// Use normalcdf from the z statistic to +infinity
p = stats.normalcdf(z, Infinity, 0, 1);
}
// Multiply the P-value by two if you're doing a not equal test
if (inequality === 'notequal') {
p *= 2;
}
return {
z: z,
p: p
};
};
// Computes a 1-mean z-interval.
//
// sigma - The population standard deviation.
// xBar - The sample mean.
// n - The sample size.
// level - The confidence level (between 0 and 1, exclusive).
//
// Returns an object with the low, high, and margin of error (moe).
stats.ZInterval = function(sigma, xBar, n, level) {
// Compute the margin of error
var moe = -stats.invNorm((1 - level) / 2) * sigma / Math.sqrt(n);
return {
low: xBar - moe,
high: xBar + moe,
moe: moe
};
};
// Export the stats object
// =================================================
if (typeof define === 'function') {
// Expose to AMD loaders
define(function() {
return stats;
});
} else if (typeof module !== 'undefined' && module.exports) {
// Expose to Node and similar environments
module.exports = stats;
} else {
// Just write to window (or whatever is the root object)
root.stats = stats;
}
}(this));

48
site/real_game/node_modules/statsjs/package.json generated vendored Normal file
View File

@ -0,0 +1,48 @@
{
"name": "statsjs",
"description": "Provides functions for many of the statistical operations that you might need",
"version": "1.0.7",
"author": "Angus Gibbs (http://angusgibbs.com)",
"homepage": "http://github.com/angusgibbs/statsjs",
"keywords": [
"math",
"stats",
"statistics",
"average",
"mean",
"min",
"max",
"standard",
"deviation",
"regression",
"quartile",
"median",
"outliers",
"factorial",
"probability",
"permutation",
"combination",
"binomial",
"geometric",
"normal",
"z-test"
],
"repository": {
"type": "git",
"url": "git://github.com/angusgibbs/statsjs.git"
},
"bugs": {
"url": "http://github.com/angusgibbs/statsjs/issues"
},
"licenses": [
{
"type": "MIT",
"url": "http://github.com/angusgibbs/statsjs/blob/master/LICENSE"
}
],
"main": "lib/stats",
"devDependencies": {
"expect.js": "git://github.com/angusgibbs/expect.js.git",
"mocha": "^1.4.3"
}
}

View File

@ -6,7 +6,11 @@
"": {
"dependencies": {
"@rollup/rollup-darwin-arm64": "^4.21.0",
"cannon-es": "^0.20.0",
"rollup": "^4.21.0",
"stats": "^1.0.0",
"stats-js": "^1.0.1",
"statsjs": "^1.0.7",
"three": "^0.167.1",
"vite": "^5.4.1"
}
@ -592,6 +596,20 @@
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
"license": "MIT"
},
"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/commander": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-0.5.2.tgz",
"integrity": "sha512-/IKo89++b1UhClEhWvKk00gKgw6iwvwD8TOPTqqN9AyvjgPCnf9OrjnDNY3dPDOj+K+OhN9SRjYQH0AfX0bROw==",
"engines": {
"node": ">= 0.4.x"
}
},
"node_modules/esbuild": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
@ -740,6 +758,31 @@
"node": ">=0.10.0"
}
},
"node_modules/stats": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/stats/-/stats-1.0.0.tgz",
"integrity": "sha512-YmKiMSrDaYA8Iu8/mPbZQmQLfzUrCstea60zPLkBMjpUveRh89GLipU/7AuMRAAX3aMmnseSuJtkgpPv29VoqA==",
"dependencies": {
"commander": "0.5.2"
},
"bin": {
"stats": "bin/stats"
},
"engines": {
"node": ">=0.4.x"
}
},
"node_modules/stats-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/stats-js/-/stats-js-1.0.1.tgz",
"integrity": "sha512-EAwEFghGNv8mlYC4CZzI5kWghsnP8uBKXw6VLRHtXkOk5xySfUKLTqTkjgJFfDluIkf/O7eZwi5MXP50VeTbUg==",
"license": "MIT"
},
"node_modules/statsjs": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/statsjs/-/statsjs-1.0.7.tgz",
"integrity": "sha512-fch+88pDPk8y4BwFwStMQR52vgJnrTHPtY15UBSkR8QAAjVBkntrFIiuDTRdknoIabfMEF7qaGhOBI+V4RtMkA=="
},
"node_modules/three": {
"version": "0.167.1",
"resolved": "https://registry.npmjs.org/three/-/three-0.167.1.tgz",

View File

@ -4,7 +4,11 @@
},
"dependencies": {
"@rollup/rollup-darwin-arm64": "^4.21.0",
"cannon-es": "^0.20.0",
"rollup": "^4.21.0",
"stats": "^1.0.0",
"stats-js": "^1.0.1",
"statsjs": "^1.0.7",
"three": "^0.167.1",
"vite": "^5.4.1"
}