├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── box2d ├── .gitignore ├── Box2D.idl ├── LICENSE.wasm-feature-detect.Apache.txt ├── LICENSE.zlib.txt ├── README.dev.md ├── README.md ├── build_all.sh ├── build_idl_bindings.sh ├── build_makefile.sh ├── build_typings.sh ├── build_wasm.sh ├── clean.sh ├── glue_stub.cpp ├── glue_stub.js ├── package.json └── tsconfig.json ├── bun.lockb ├── client ├── assets │ ├── fonts │ │ ├── Urbanist-Black.woff2 │ │ ├── Urbanist-BlackItalic.woff2 │ │ ├── Urbanist-Bold.woff2 │ │ ├── Urbanist-BoldItalic.woff2 │ │ ├── Urbanist-ExtraBold.woff2 │ │ ├── Urbanist-ExtraBoldItalic.woff2 │ │ ├── Urbanist-ExtraLight.woff2 │ │ ├── Urbanist-ExtraLightItalic.woff2 │ │ ├── Urbanist-Italic.woff2 │ │ ├── Urbanist-Light.woff2 │ │ ├── Urbanist-LightItalic.woff2 │ │ ├── Urbanist-Medium.woff2 │ │ ├── Urbanist-MediumItalic.woff2 │ │ ├── Urbanist-Regular.woff2 │ │ ├── Urbanist-SemiBold.woff2 │ │ ├── Urbanist-SemiBoldItalic.woff2 │ │ ├── Urbanist-Thin.woff2 │ │ └── Urbanist-ThinItalic.woff2 │ ├── music │ │ ├── infinity.ogg │ │ ├── menu.ogg │ │ ├── menu_slowed.ogg │ │ ├── stars.ogg │ │ ├── stars_slowed.ogg │ │ ├── stasis.ogg │ │ ├── techno_vibes.ogg │ │ └── techno_vibes_slowed.ogg │ ├── sounds │ │ ├── button_down.wav │ │ ├── button_up.wav │ │ ├── deny.wav │ │ ├── ground.wav │ │ ├── impact.wav │ │ ├── impact_old.wav │ │ ├── spawn_down.wav │ │ └── spawn_up.wav │ └── textures │ │ ├── add_axle.png │ │ ├── add_circle.png │ │ ├── add_circle_old.png │ │ ├── add_fixed_joint.png │ │ ├── add_particle.png │ │ ├── add_polygon.png │ │ ├── add_polygon_old.png │ │ ├── add_rectangle.png │ │ ├── add_rectangle_old.png │ │ ├── add_spring.png │ │ ├── add_spring_old.png │ │ ├── basic_car.png │ │ ├── body.png │ │ ├── body_purple.png │ │ ├── car.png │ │ ├── cursor.png │ │ ├── cursor.svg │ │ ├── cursor_old.png │ │ ├── laserpen.png │ │ ├── person.png │ │ ├── person_purple.png │ │ ├── select.png │ │ ├── spring.png │ │ ├── spring.svg │ │ ├── tools │ │ ├── axle.png │ │ ├── bolt.png │ │ ├── box.png │ │ ├── brush.png │ │ ├── chain.png │ │ ├── circle.png │ │ ├── cut.png │ │ ├── drag.png │ │ ├── eraser.png │ │ ├── fixjoint.png │ │ ├── gear.png │ │ ├── hinge.png │ │ ├── laserpen.png │ │ ├── move.png │ │ ├── pan.png │ │ ├── plane.png │ │ ├── polygon.png │ │ ├── rotate.png │ │ ├── scale.png │ │ ├── sketch.png │ │ ├── spring.png │ │ ├── texture.png │ │ ├── thruster.png │ │ ├── tracer.png │ │ └── zoom.png │ │ └── unknown.png ├── icons │ ├── add-box.svg │ ├── add-circle.svg │ ├── add-polygon.svg │ ├── add-spring.svg │ ├── axle.svg │ ├── bolt.svg │ ├── polygon.svg │ └── spring.svg ├── index.css ├── index.html ├── manifest.json ├── src │ ├── Example.ts │ ├── SimuloClient.ts │ ├── SimuloClientController │ │ ├── editor.ts │ │ └── index.ts │ ├── SimuloCreatingObject.ts │ ├── SimuloJointData.ts │ ├── SimuloLocalClient.ts │ ├── SimuloNetworkClient │ │ ├── index.ts │ │ └── socket.io.esm.min.js │ ├── SimuloNetworkServer.ts │ ├── SimuloObjectData.ts │ ├── SimuloPhysicsServer.ts │ ├── SimuloRoom.ts │ ├── SimuloServerController.ts │ ├── SimuloShape.ts │ ├── SimuloStep.ts │ ├── SimuloText.ts │ ├── SimuloTheme.ts │ ├── SimuloViewer.ts │ ├── SimuloViewerCanvas │ │ ├── index.ts │ │ └── renderer.ts │ ├── SimuloViewerWebGL │ │ └── index.ts │ ├── css.d.ts │ ├── html.d.ts │ ├── index.ts │ ├── themes.ts │ ├── utils.ts │ └── worker.ts ├── sw.js └── tsconfig.json ├── media ├── banner.png ├── banner.svg ├── icon change.svg ├── icon change.svg.2023_06_22_21_50_31.3.svg ├── icon.png ├── icon.svg ├── icon_192.png ├── icon_bg.png ├── icon_fg.png ├── icon_no_bg.png ├── icon_no_bg.svg ├── icon_small.png ├── icon_smaller.png ├── icon_square.png ├── icon_square.svg ├── icon_square_new.svg.2023_06_22_21_50_31.0.svg ├── icon_square_old.png ├── icon_square_old.svg ├── imulo.png ├── imulo.svg ├── limegreen.svg ├── logo.png ├── logo.svg ├── maskable_icon_x128.png ├── maskable_icon_x192.png ├── maskable_icon_x512.png └── urple.svg ├── newcss.css ├── other ├── Inkscape Workspace.svg ├── box2d-wasm-7.0.0.tgz └── tsedition ├── package-lock.json ├── package.json ├── scripts ├── all-pre.ts ├── build.ts ├── deploy.js ├── desktop.ts ├── lib.ts ├── tsconfig.json └── watch.ts ├── server ├── src │ ├── index.ts │ └── log.ts └── tsconfig.json └── website ├── assets ├── fonts │ ├── Urbanist-Black.woff2 │ ├── Urbanist-BlackItalic.woff2 │ ├── Urbanist-Bold.woff2 │ ├── Urbanist-BoldItalic.woff2 │ ├── Urbanist-ExtraBold.woff2 │ ├── Urbanist-ExtraBoldItalic.woff2 │ ├── Urbanist-ExtraLight.woff2 │ ├── Urbanist-ExtraLightItalic.woff2 │ ├── Urbanist-Italic.woff2 │ ├── Urbanist-Light.woff2 │ ├── Urbanist-LightItalic.woff2 │ ├── Urbanist-Medium.woff2 │ ├── Urbanist-MediumItalic.woff2 │ ├── Urbanist-Regular.woff2 │ ├── Urbanist-SemiBold.woff2 │ ├── Urbanist-SemiBoldItalic.woff2 │ ├── Urbanist-Thin.woff2 │ └── Urbanist-ThinItalic.woff2 ├── sounds │ ├── button_down.wav │ ├── button_up.wav │ ├── deny.wav │ ├── ground.wav │ ├── impact.wav │ ├── impact_old.wav │ ├── spawn_down.wav │ └── spawn_up.wav └── textures │ ├── add_axle.png │ ├── add_circle.png │ ├── add_circle_old.png │ ├── add_fixed_joint.png │ ├── add_particle.png │ ├── add_polygon.png │ ├── add_polygon_old.png │ ├── add_rectangle.png │ ├── add_rectangle_old.png │ ├── add_spring.png │ ├── add_spring_old.png │ ├── body.png │ ├── body_purple.png │ ├── car.png │ ├── cursor.png │ ├── person.png │ ├── person_purple.png │ ├── select.png │ ├── spring.png │ ├── spring.svg │ ├── tools │ ├── box.png │ ├── brush.png │ ├── chain.png │ ├── circle.png │ ├── cut.png │ ├── drag.png │ ├── eraser.png │ ├── fixjoint.png │ ├── gear.png │ ├── hinge.png │ ├── laserpen.png │ ├── move.png │ ├── pan.png │ ├── plane.png │ ├── polygon.png │ ├── rotate.png │ ├── scale.png │ ├── sketch.png │ ├── spring.png │ ├── texture.png │ ├── thruster.png │ ├── tracer.png │ └── zoom.png │ └── unknown.png ├── bg.png ├── bg_old.png ├── img1.png ├── img2.png ├── img3.png ├── index.css └── index.html /.gitattributes: -------------------------------------------------------------------------------- 1 | # Example of a `.gitattributes` file which reclassifies `.rb` files as Java: 2 | *.ts linguist-language=TypeScript 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | node_modules 3 | node_modules/* 4 | log.txt 5 | dist/ 6 | dist 7 | dist/* 8 | build-log.json -------------------------------------------------------------------------------- /box2d/.gitignore: -------------------------------------------------------------------------------- 1 | /build*/ 2 | /node_modules/ 3 | # distributions made with npm pack 4 | *.tgz 5 | *.tar.gz 6 | # copies of build artifacts 7 | /dist/Box2D.d.ts 8 | /dist/es/Box2D.js 9 | /dist/es/Box2D.wasm 10 | /dist/es/Box2D.wasm.map 11 | /dist/es/Box2D.simd.js 12 | /dist/es/Box2D.simd.wasm 13 | /dist/es/Box2D.simd.wasm.map 14 | /dist/umd/Box2D.js 15 | /dist/umd/Box2D.wasm 16 | /dist/umd/Box2D.wasm.map 17 | /dist/umd/Box2D.simd.js 18 | /dist/umd/Box2D.simd.wasm 19 | /dist/umd/Box2D.simd.wasm.map 20 | # integration test for AMD modules which I didn't feel like putting anywhere more formal 21 | /amd/ -------------------------------------------------------------------------------- /box2d/LICENSE.zlib.txt: -------------------------------------------------------------------------------- 1 | Zlib License 2 | 3 | Copyright (c) 2020 Alex Birch 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /box2d/README.dev.md: -------------------------------------------------------------------------------- 1 | ## Developing this package 2 | 3 | Ensure that you have a recent [emscripten](https://emscripten.org/) installed. 4 | 5 | **Requires Emscripten 2.0.17 or higher** 6 | 7 | ### Overview 8 | 9 | Navigate to `/box2d-wasm`, then: 10 | 11 | ```bash 12 | export TARGET_TYPE=Debug 13 | # if you installed emscripten via emsdk: source emsdk_env.sh, then configure tools directory like so: 14 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/tools/webidl_binder.py")" 15 | # if you installed emscripten via brew: configure tools directory like so: 16 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../libexec/tools/webidl_binder.py")" 17 | # if you installed emscripten via Nix: configure tools directory like so: 18 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../share/emscripten/tools/webidl_binder.py")" 19 | export PYTHON3="${EMSDK_PYTHON:-"$(which python3)"}" 20 | ./build_all.sh 21 | ``` 22 | 23 | ### Step-by-step 24 | 25 | If you're prefer not to use [`build_all.sh`](build_all.sh), here's each step laid bare. 26 | 27 | Navigate to `/box2d-wasm`, then: 28 | 29 | ```bash 30 | mkdir -p build/common 31 | pushd build 32 | pushd common 33 | 34 | # ensure PYTHON3 environment variable points to a Python 3 binary: 35 | export PYTHON3="${EMSDK_PYTHON:-"$(which python3)"}" 36 | 37 | # ensure WEBIDL_BINDER environment variable points to the location of the Emscripten tool, webidl_binder.py 38 | # you can determine this based on the location of the `emcc` executable on your PATH. 39 | # if you installed emscripten via emsdk: source emsdk_env.sh, then set the variable like so: 40 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/tools/webidl_binder.py")" 41 | # if you installed emscripten via brew: set the variable like so: 42 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../libexec/tools/webidl_binder.py")" 43 | # if you installed emscripten via Nix: configure tools directory like so: 44 | export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../share/emscripten/tools/webidl_binder.py")" 45 | 46 | # use Box2D.idl to create ./box2d_glue.{js,cpp} for invoking functionality from libbox2d 47 | ../../build_idl_bindings.sh 48 | 49 | # generate Box2D.d.ts from Box2D.idl 50 | ../../build_typings.sh 51 | 52 | popd 53 | 54 | # TARGET_TYPE 55 | # Debug: fast compilation (for fast iteration when developing locally) 56 | # Release: optimized for high-performance (longer compile time, for release builds) 57 | # RelWithDebInfo: Release, but with debug source-maps (and with closure optimizations disabled) 58 | # used for C++ -> LLVM IR, and for LLVM IR -> WASM. Debug 59 | # both provided for your copy-paste convenience 60 | TARGET_TYPE=RelWithDebInfo 61 | TARGET_TYPE=Release 62 | TARGET_TYPE=Debug 63 | 64 | # pick one 65 | FLAVOUR=standard 66 | FLAVOUR=simd 67 | 68 | FLAVOUR_DIR="flavour/$FLAVOUR" 69 | 70 | mkdir -p "$FLAVOUR_DIR" 71 | pushd "$FLAVOUR_DIR" 72 | 73 | # generate Makefiles compatible with emscripten 74 | FLAVOUR="$FLAVOUR" TARGET_TYPE="$TARGET_TYPE" ../../../build_makefile.sh 75 | 76 | # compile C++ to LLVM IR (creates ./bin/libbox2d.a archive) 77 | emmake make 78 | 79 | # generate Box2D.{wasm,js} from glue code + libbox2d.a 80 | FLAVOUR="$FLAVOUR" TARGET_TYPE="$TARGET_TYPE" ../../../build_wasm.sh 81 | 82 | popd 83 | ``` -------------------------------------------------------------------------------- /box2d/README.md: -------------------------------------------------------------------------------- 1 | # box2d-wasm 2 | 3 | Box2D compiled to WebAssembly. [Demo](https://birchlabs.co.uk/box2d-wasm/demo/). 4 | _Demo includes sourcemaps to original C++ source._ 5 | 6 | Compatibility: Box2D [v2.4.1](https://github.com/erincatto/box2d/releases/tag/v2.4.1) 7 | 8 | | Asset | Purpose | Size | Size (.gz) | 9 | | --- | --- | --- | --- | 10 | | `Box2D.js` | Provides helpers for you to invoke functionality from `Box2D.wasm` | 290kB | **40kB** | 11 | | `Box2D.wasm` | Box2D physics engine | 213kB | **78kB** | 12 | 13 | Detailed TypeScript declarations are included (generated via [`webidl-to-ts`](../webidl-to-ts) from [WebIDL bindings](../box2d-wasm/Box2D.idl)). 14 | 15 | ## Installation 16 | 17 | Install the [`box2d-wasm` npm package](https://www.npmjs.com/package/box2d-wasm) 18 | 19 | ```bash 20 | npm i --save box2d-wasm 21 | ``` 22 | 23 | Then check out the [documentation](../docs). 24 | 25 | ## License 26 | 27 | [Zlib-licensed](LICENSE.zlib.txt). 28 | Links against MIT-licensed code from Erin Catto's [box2d](https://github.com/erincatto/box2d). 29 | Compiles Zlib-licensed code from Alon Zakai's [box2d-js](https://github.com/kripken/box2d.js). 30 | 31 | ## Developing this package 32 | 33 | See [`README.dev.md`](README.dev.md). -------------------------------------------------------------------------------- /box2d/build_all.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | # This script just does what the README says, except with some extra validation and interactivity. 6 | # If you're more interested in going through step-by-step, and avoiding rebuilds of files you've 7 | # already built: you'll probably prefer to cherry-pick lines from the README. 8 | 9 | Red='\033[0;31m' 10 | Purple='\033[0;35m' 11 | NC='\033[0m' # No Color 12 | 13 | if ! [[ "$PWD" -ef "$DIR" ]]; then 14 | >&2 echo -e "${Red}This script is meant to be run from /box2d-wasm${NC}" 15 | exit 1 16 | fi 17 | 18 | mkdir -p "build/common" 19 | pushd "build/common" 20 | 21 | # use Box2D.idl to create ./box2d_glue.{js,cpp} for invoking functionality from libbox2d 22 | set -x 23 | "$DIR/build_idl_bindings.sh" 24 | { set +x; } 2>&- 25 | >&2 echo 26 | 27 | set -x 28 | "$DIR/build_typings.sh" 29 | { set +x; } 2>&- 30 | 31 | popd 32 | 33 | FLAVOURS=(standard simd) 34 | 35 | for i in {0..1} 36 | do 37 | FLAVOUR="${FLAVOURS["$i"]}" 38 | 39 | # use JUST_SIMD=1 to save time when prototyping 40 | if [[ "$JUST_SIMD" = "1" && "$FLAVOUR" != "simd" ]]; then 41 | >&2 echo -e "\nSkipping '$FLAVOUR' flavour build because JUST_SIMD is set." 42 | continue 43 | fi 44 | 45 | 46 | FLAVOUR_DIR="build/flavour/$FLAVOUR" 47 | >&2 echo -e "\nMaking '$FLAVOUR' flavour in ./$FLAVOUR_DIR directory" 48 | mkdir -p "$FLAVOUR_DIR" 49 | pushd "$FLAVOUR_DIR" 50 | 51 | set -x 52 | FLAVOUR="$FLAVOUR" "$DIR/build_makefile.sh" 53 | { set +x; } 2>&- 54 | 55 | >&2 echo -e '\nCompiling C++ to LLVM IR (creates ./build/bin/libbox2d.a archive)' 56 | set -x 57 | emmake make 58 | { set +x; } 2>&- 59 | >&2 echo 60 | 61 | # generate Box2D_*.{wasm,js} from glue code + libbox2d.a 62 | set -x 63 | FLAVOUR="$FLAVOUR" "$DIR/build_wasm.sh" 64 | { set +x; } 2>&- 65 | 66 | >&2 echo -e "Completed '$FLAVOUR' flavour" 67 | 68 | popd 69 | done -------------------------------------------------------------------------------- /box2d/build_idl_bindings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | Red='\033[0;31m' 6 | Purple='\033[0;35m' 7 | NC='\033[0m' # No Color 8 | 9 | if ! [[ "$PWD" -ef "$DIR/build/common" ]]; then 10 | >&2 echo -e "${Red}This script is meant to be run from /box2d-wasm/build/common${NC}" 11 | exit 1 12 | fi 13 | 14 | if [ -f "${WEBIDL_BINDER-}" ]; then 15 | >&2 echo -e "Using the following webidl_binder.py location: $WEBIDL_BINDER" 16 | else 17 | >&2 echo -e "${Red}WebIDL binder (the Emscripten tool, webidl_binder.py) was not found at expected location of $WEBIDL_BINDER${NC}" 18 | >&2 echo -e "You can set WEBIDL_BINDER based on the location of an Emscripten command on your PATH." 19 | >&2 echo -e "if you installed emscripten via emsdk: source emsdk_env.sh, then set the variable like so:" 20 | >&2 echo -e "${Purple}"'export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/tools/webidl_binder.py")"'"${NC}" 21 | >&2 echo -e "if you installed emscripten via brew: set the variable like so:" 22 | >&2 echo -e "${Purple}"'export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../libexec/tools/webidl_binder.py")"'"${NC}" 23 | >&2 echo -e "if you installed emscripten via Nix: set the variable like so:" 24 | >&2 echo -e "${Purple}"'export WEBIDL_BINDER="$(realpath "$(dirname "$(realpath "$(which emcc)")")/../share/emscripten/tools/webidl_binder.py")"'"${NC}" 25 | fi 26 | 27 | if [[ -f "${PYTHON3-}" && -x "${PYTHON3-}" ]]; then 28 | >&2 echo -e "Using the following Python binary: $PYTHON3" 29 | else 30 | >&2 echo -e "${Red}PYTHON3 variable empty/unset/non-executable. Please set to the location of a Python 3 binary.${NC}" 31 | >&2 echo -e "You can set PYTHON3 based on the location of a python3 binary on your PATH like so:" 32 | >&2 echo -e "${Purple}"'export PYTHON3="${EMSDK_PYTHON:-"$(which python3)"}"'"${NC}" 33 | exit 1 34 | fi 35 | 36 | set -x 37 | "$PYTHON3" "$WEBIDL_BINDER" "$DIR/Box2D.idl" box2d_glue 38 | 39 | # Fix for Emscripten 2.0.18+ (we have no main function so cannot use addOnPreMain) 40 | sed -i'.original.js' '/addOnPreMain/ s/addOnPreMain/addOnPreRun/' box2d_glue.js -------------------------------------------------------------------------------- /box2d/build_makefile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | Red='\033[0;31m' 6 | Purple='\033[0;35m' 7 | NC='\033[0m' # No Color 8 | 9 | CMAKE_CXX_FLAGS=() 10 | case "$FLAVOUR" in 11 | standard) 12 | ;; 13 | simd) 14 | CMAKE_CXX_FLAGS=(${CMAKE_CXX_FLAGS[@]} -msimd128) 15 | ;; 16 | *) 17 | >&2 echo -e "${Red}FLAVOUR not set.${NC}" 18 | >&2 echo -e "Please set FLAVOUR to 'standard' or 'simd'. For example, with:" 19 | >&2 echo -e "${Purple}export FLAVOUR='simd'${NC}" 20 | exit 1 21 | ;; 22 | esac 23 | 24 | if ! [[ "$PWD" -ef "$DIR/build/flavour/$FLAVOUR" ]]; then 25 | >&2 echo -e "${Red}This script is meant to be run from /box2d-wasm/build/flavour/$FLAVOUR${NC}" 26 | exit 1 27 | fi 28 | 29 | >&2 echo -e '\nGenerating Makefile with emcmake' 30 | 31 | case "$TARGET_TYPE" in 32 | RelWithDebInfo | Release | Debug) 33 | ;; 34 | *) 35 | >&2 echo -e "${Red}TARGET_TYPE not set.${NC}" 36 | >&2 echo -e "Please set TARGET_TYPE to 'Debug', 'Release', or 'RelWithDebInfo'. For example, with:" 37 | >&2 echo -e "${Purple}export TARGET_TYPE='Debug'${NC}" 38 | exit 1 39 | ;; 40 | esac 41 | >&2 echo -e "TARGET_TYPE is $TARGET_TYPE" 42 | 43 | set -x 44 | emcmake cmake -DCMAKE_BUILD_TYPE="$TARGET_TYPE" -DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS[@]}" "$DIR/../box2d" -DBOX2D_BUILD_UNIT_TESTS=OFF -DBOX2D_BUILD_DOCS=OFF -DBOX2D_BUILD_TESTBED=OFF -------------------------------------------------------------------------------- /box2d/build_typings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | Red='\033[0;31m' 6 | Purple='\033[0;35m' 7 | NC='\033[0m' # No Color 8 | 9 | if ! [[ "$PWD" -ef "$DIR/build/common" ]]; then 10 | >&2 echo -e "${Red}This script is meant to be run from /box2d-wasm/build/common${NC}" 11 | exit 1 12 | fi 13 | 14 | : "${WEBIDL_TO_TS:="$DIR/node_modules/webidl-to-ts"}" 15 | if test -d "${WEBIDL_TO_TS-}"; then 16 | >&2 echo -e "webidl-to-ts found at: $WEBIDL_TO_TS" 17 | else 18 | >&2 echo -e "${Red}webidl-to-ts directory not found at: $WEBIDL_TO_TS${NC}" 19 | >&2 echo -e "A symlink node_modules/webidl-to-ts should be created when you install this package (box2d-wasm) via pnpm:${NC}" 20 | >&2 echo -e "${Purple}pnpm i${NC}" 21 | exit 1 22 | fi 23 | 24 | set -x 25 | # change directory so that Node module resolution will search for its dependencies releative to where webidl-to-ts is installed, not box2d-wasm 26 | cd $WEBIDL_TO_TS 27 | # requires Node 14.0.0 for running ES modules 28 | exec node --experimental-specifier-resolution=node --harmony "dist/index.js" -f "$DIR/Box2D.idl" -n Box2D -o "$DIR/dist/Box2D.d.ts" -------------------------------------------------------------------------------- /box2d/build_wasm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -eo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | Red='\033[0;31m' 6 | Green='\033[0;32m' 7 | Blue='\033[0;34m' 8 | Purple='\033[0;35m' 9 | NC='\033[0m' # No Color 10 | 11 | BASENAME=Box2D 12 | FLAVOUR_EMCC_OPTS=() 13 | case "$FLAVOUR" in 14 | standard) 15 | ;; 16 | simd) 17 | BASENAME="$BASENAME.simd" 18 | FLAVOUR_EMCC_OPTS=(${FLAVOUR_EMCC_OPTS[@]} -msimd128) 19 | ;; 20 | *) 21 | >&2 echo -e "${Red}FLAVOUR not set.${NC}" 22 | >&2 echo -e "Please set FLAVOUR to 'standard' or 'simd'. For example, with:" 23 | >&2 echo -e "${Purple}export FLAVOUR='simd'${NC}" 24 | exit 1 25 | ;; 26 | esac 27 | 28 | if ! [[ "$PWD" -ef "$DIR/build/flavour/$FLAVOUR" ]]; then 29 | >&2 echo -e "${Red}This script is meant to be run from /box2d-wasm/build/flavour/$FLAVOUR${NC}" 30 | exit 1 31 | fi 32 | 33 | # we used to use -s ENVIRONMENT=web for a slightly smaller build, until Node.js compatibility was requested in https://github.com/Birch-san/box2d-wasm/issues/8 34 | EMCC_OPTS=( 35 | -fno-rtti 36 | -s MODULARIZE=1 37 | -s EXPORT_NAME=Box2D 38 | -s ALLOW_TABLE_GROWTH=1 39 | --memory-init-file 0 40 | -s FILESYSTEM=0 41 | -s SUPPORT_LONGJMP=0 42 | -s EXPORTED_FUNCTIONS=_malloc,_free 43 | -s ALLOW_MEMORY_GROWTH=1 44 | ${FLAVOUR_EMCC_OPTS[@]} 45 | ) 46 | DEBUG_OPTS=( 47 | -g3 48 | ) 49 | RELEASE_OPTS=(-O3) 50 | 51 | case "$TARGET_TYPE" in 52 | Debug) 53 | EMCC_OPTS=( 54 | ${EMCC_OPTS[@]} 55 | ${DEBUG_OPTS[@]} 56 | -s ASSERTIONS=2 57 | -s DEMANGLE_SUPPORT=1 58 | ) 59 | ;; 60 | 61 | RelWithDebInfo) 62 | # consider setting --source-map-base if you know where 63 | # Box2D will be served from. 64 | EMCC_OPTS=( 65 | ${EMCC_OPTS[@]} 66 | ${RELEASE_OPTS[@]} 67 | ${DEBUG_OPTS[@]} 68 | ) 69 | ;; 70 | 71 | Release) 72 | EMCC_OPTS=( 73 | ${EMCC_OPTS[@]} 74 | ${RELEASE_OPTS[@]} 75 | -flto 76 | --closure 1 77 | -s IGNORE_CLOSURE_COMPILER_ERRORS=1 78 | ) 79 | ;; 80 | 81 | *) 82 | >&2 echo -e "${Red}TARGET_TYPE not set.${NC}" 83 | >&2 echo -e "Please set TARGET_TYPE to 'Debug' or 'Release'. For example, with:" 84 | >&2 echo -e "${Purple}export TARGET_TYPE='Debug'${NC}" 85 | exit 1 86 | ;; 87 | esac 88 | >&2 echo -e "TARGET_TYPE is $TARGET_TYPE" 89 | 90 | BARE_WASM="$BASENAME.bare.wasm" 91 | 92 | >&2 echo -e "${Blue}Building bare WASM${NC}" 93 | set -x 94 | emcc "$DIR/glue_stub.cpp" bin/libbox2d.a -I "$DIR/../box2d/include" "${EMCC_OPTS[@]}" --oformat=bare -o "$BARE_WASM" 95 | { set +x; } 2>&- 96 | >&2 echo -e "${Green}Successfully built $BARE_WASM${NC}\n" 97 | 98 | UMD_DIR="$DIR/dist/umd" 99 | ES_DIR="$DIR/dist/es" 100 | 101 | >&2 echo -e "${Blue}Building post-link targets${NC}" 102 | 103 | LINK_OPTS=(--post-link "$BARE_WASM" --post-js "$DIR/build/common/box2d_glue.js" --post-js "$DIR/glue_stub.js" ${EMCC_OPTS[@]}) 104 | 105 | ES_FILE="$ES_DIR/$BASENAME.js" 106 | >&2 echo -e "${Blue}Building ES module, $ES_DIR/$BASENAME.{js,wasm}${NC}" 107 | set -x 108 | emcc "${LINK_OPTS[@]}" -s EXPORT_ES6=1 -o "$ES_FILE" 109 | { set +x; } 2>&- 110 | >&2 echo -e "${Green}Successfully built $ES_DIR/$BASENAME.{js,wasm}${NC}\n" 111 | 112 | UMD_FILE="$UMD_DIR/$BASENAME.js" 113 | # cheeky text-replace to save time. 114 | # only works if the text-substitution is exactly as we expected (so may fail silently depending on Emscripten version or config) 115 | if [ "$BUILD_UMD_VIA_TEXT_REPLACE" = "1" ]; then 116 | >&2 echo -e "${Blue}Building UMD module, $UMD_DIR/$BASENAME.{js,wasm} by replacing header & footer of ES module${NC}" 117 | escape_for_sed_replace () { 118 | echo "$1" | sed -e 's/&/\\\&/g' -e '$!s/$/\\n/' | tr -d '\n' 119 | } 120 | 121 | ES6_HEADER=' var _scriptDir = import.meta.url;' 122 | UMD_HEADER=" var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; 123 | if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename;" 124 | UMD_HEADER_ESCAPED=`escape_for_sed_replace "$UMD_HEADER"` 125 | 126 | ES6_FOOTER='export default Box2D;' 127 | UMD_FOOTER="if (typeof exports === 'object' && typeof module === 'object') 128 | module.exports = Box2D; 129 | else if (typeof define === 'function' && define['amd']) 130 | define([], function() { return Box2D; }); 131 | else if (typeof exports === 'object') 132 | exports['Box2D'] = Box2D; 133 | " 134 | UMD_FOOTER_ESCAPED=`escape_for_sed_replace "$UMD_FOOTER"` 135 | 136 | sed -e "s/^$ES6_HEADER$/$UMD_HEADER_ESCAPED/" -e "s/^$ES6_FOOTER$/$UMD_FOOTER_ESCAPED/" "$ES_FILE" > "$UMD_FILE" 137 | cp "$ES_DIR/$BASENAME.wasm" "$UMD_DIR" 138 | else 139 | >&2 echo -e "${Blue}Building UMD module, $UMD_DIR/$BASENAME.{js,wasm} from scratch${NC}" 140 | set -x 141 | emcc "${LINK_OPTS[@]}" -o "$UMD_FILE" 142 | { set +x; } 2>&- 143 | fi 144 | >&2 echo -e "${Green}Successfully built $UMD_DIR/$BASENAME.{js,wasm}${NC}\n" -------------------------------------------------------------------------------- /box2d/clean.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 4 | 5 | rm -rf "$DIR"/build 6 | rm -f "$DIR"/dist/Box2D.d.ts 7 | rm -f "$DIR"/dist/{es,umd}/Box2D{.simd,}.{wasm,js} -------------------------------------------------------------------------------- /box2d/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "liquidfun-wasm", 3 | "version": "7.0.0", 4 | "description": "Liquidfun fork of Box2D compiled to WebAssembly", 5 | "module": "dist/es/entry.js", 6 | "main": "dist/umd/entry.js", 7 | "files": [ 8 | "dist/Box2D.d.ts", 9 | "dist/Box2DModule.d.ts", 10 | "dist/Box2DModuleAugmentations.d.ts", 11 | "dist/es/entry.d.ts", 12 | "dist/es/entry.js", 13 | "dist/umd/entry.d.ts", 14 | "dist/umd/entry.js", 15 | "dist/es/Box2D.d.ts", 16 | "dist/es/Box2D.js", 17 | "dist/es/Box2D.wasm", 18 | "dist/es/Box2D.simd.d.ts", 19 | "dist/es/Box2D.simd.js", 20 | "dist/es/Box2D.simd.wasm", 21 | "dist/umd/Box2D.d.ts", 22 | "dist/umd/Box2D.js", 23 | "dist/umd/Box2D.wasm", 24 | "dist/umd/Box2D.simd.d.ts", 25 | "dist/umd/Box2D.simd.js", 26 | "dist/umd/Box2D.simd.wasm" 27 | ], 28 | "types": "dist/Box2DModule.d.ts", 29 | "repository": { 30 | "url": "https://github.com/Birch-san/box2d-wasm/tree/liquidfun/box2d-wasm" 31 | }, 32 | "scripts": { 33 | "test": "echo \"Error: no test specified\" && exit 1", 34 | "build_typings": "npm start --prefix node_modules/webidl-to-ts -- -f $(realpath Box2D.idl) -n Box2D -o $(realpath .)/build/Box2D.d.ts", 35 | "build": "./build_all.sh" 36 | }, 37 | "devDependencies": { 38 | "webidl-to-ts": "workspace:*" 39 | }, 40 | "dependencies": { 41 | "@types/emscripten": "^1.39.6" 42 | }, 43 | "author": "Alex Birch", 44 | "license": "Zlib" 45 | } 46 | -------------------------------------------------------------------------------- /box2d/tsconfig.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/box2d/tsconfig.json -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/bun.lockb -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Black.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-BlackItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Bold.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-BoldItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-ExtraBold.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-ExtraLight.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Italic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Light.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-LightItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Medium.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-MediumItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Regular.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-SemiBold.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-Thin.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/Urbanist-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/fonts/Urbanist-ThinItalic.woff2 -------------------------------------------------------------------------------- /client/assets/music/infinity.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/infinity.ogg -------------------------------------------------------------------------------- /client/assets/music/menu.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/menu.ogg -------------------------------------------------------------------------------- /client/assets/music/menu_slowed.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/menu_slowed.ogg -------------------------------------------------------------------------------- /client/assets/music/stars.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/stars.ogg -------------------------------------------------------------------------------- /client/assets/music/stars_slowed.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/stars_slowed.ogg -------------------------------------------------------------------------------- /client/assets/music/stasis.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/stasis.ogg -------------------------------------------------------------------------------- /client/assets/music/techno_vibes.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/techno_vibes.ogg -------------------------------------------------------------------------------- /client/assets/music/techno_vibes_slowed.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/music/techno_vibes_slowed.ogg -------------------------------------------------------------------------------- /client/assets/sounds/button_down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/button_down.wav -------------------------------------------------------------------------------- /client/assets/sounds/button_up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/button_up.wav -------------------------------------------------------------------------------- /client/assets/sounds/deny.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/deny.wav -------------------------------------------------------------------------------- /client/assets/sounds/ground.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/ground.wav -------------------------------------------------------------------------------- /client/assets/sounds/impact.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/impact.wav -------------------------------------------------------------------------------- /client/assets/sounds/impact_old.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/impact_old.wav -------------------------------------------------------------------------------- /client/assets/sounds/spawn_down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/spawn_down.wav -------------------------------------------------------------------------------- /client/assets/sounds/spawn_up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/sounds/spawn_up.wav -------------------------------------------------------------------------------- /client/assets/textures/add_axle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_axle.png -------------------------------------------------------------------------------- /client/assets/textures/add_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_circle.png -------------------------------------------------------------------------------- /client/assets/textures/add_circle_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_circle_old.png -------------------------------------------------------------------------------- /client/assets/textures/add_fixed_joint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_fixed_joint.png -------------------------------------------------------------------------------- /client/assets/textures/add_particle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_particle.png -------------------------------------------------------------------------------- /client/assets/textures/add_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_polygon.png -------------------------------------------------------------------------------- /client/assets/textures/add_polygon_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_polygon_old.png -------------------------------------------------------------------------------- /client/assets/textures/add_rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_rectangle.png -------------------------------------------------------------------------------- /client/assets/textures/add_rectangle_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_rectangle_old.png -------------------------------------------------------------------------------- /client/assets/textures/add_spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_spring.png -------------------------------------------------------------------------------- /client/assets/textures/add_spring_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/add_spring_old.png -------------------------------------------------------------------------------- /client/assets/textures/basic_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/basic_car.png -------------------------------------------------------------------------------- /client/assets/textures/body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/body.png -------------------------------------------------------------------------------- /client/assets/textures/body_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/body_purple.png -------------------------------------------------------------------------------- /client/assets/textures/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/car.png -------------------------------------------------------------------------------- /client/assets/textures/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/cursor.png -------------------------------------------------------------------------------- /client/assets/textures/cursor.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /client/assets/textures/cursor_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/cursor_old.png -------------------------------------------------------------------------------- /client/assets/textures/laserpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/laserpen.png -------------------------------------------------------------------------------- /client/assets/textures/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/person.png -------------------------------------------------------------------------------- /client/assets/textures/person_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/person_purple.png -------------------------------------------------------------------------------- /client/assets/textures/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/select.png -------------------------------------------------------------------------------- /client/assets/textures/spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/spring.png -------------------------------------------------------------------------------- /client/assets/textures/spring.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 36 | 38 | 43 | 48 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /client/assets/textures/tools/axle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/axle.png -------------------------------------------------------------------------------- /client/assets/textures/tools/bolt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/bolt.png -------------------------------------------------------------------------------- /client/assets/textures/tools/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/box.png -------------------------------------------------------------------------------- /client/assets/textures/tools/brush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/brush.png -------------------------------------------------------------------------------- /client/assets/textures/tools/chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/chain.png -------------------------------------------------------------------------------- /client/assets/textures/tools/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/circle.png -------------------------------------------------------------------------------- /client/assets/textures/tools/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/cut.png -------------------------------------------------------------------------------- /client/assets/textures/tools/drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/drag.png -------------------------------------------------------------------------------- /client/assets/textures/tools/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/eraser.png -------------------------------------------------------------------------------- /client/assets/textures/tools/fixjoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/fixjoint.png -------------------------------------------------------------------------------- /client/assets/textures/tools/gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/gear.png -------------------------------------------------------------------------------- /client/assets/textures/tools/hinge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/hinge.png -------------------------------------------------------------------------------- /client/assets/textures/tools/laserpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/laserpen.png -------------------------------------------------------------------------------- /client/assets/textures/tools/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/move.png -------------------------------------------------------------------------------- /client/assets/textures/tools/pan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/pan.png -------------------------------------------------------------------------------- /client/assets/textures/tools/plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/plane.png -------------------------------------------------------------------------------- /client/assets/textures/tools/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/polygon.png -------------------------------------------------------------------------------- /client/assets/textures/tools/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/rotate.png -------------------------------------------------------------------------------- /client/assets/textures/tools/scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/scale.png -------------------------------------------------------------------------------- /client/assets/textures/tools/sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/sketch.png -------------------------------------------------------------------------------- /client/assets/textures/tools/spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/spring.png -------------------------------------------------------------------------------- /client/assets/textures/tools/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/texture.png -------------------------------------------------------------------------------- /client/assets/textures/tools/thruster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/thruster.png -------------------------------------------------------------------------------- /client/assets/textures/tools/tracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/tracer.png -------------------------------------------------------------------------------- /client/assets/textures/tools/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/tools/zoom.png -------------------------------------------------------------------------------- /client/assets/textures/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/assets/textures/unknown.png -------------------------------------------------------------------------------- /client/icons/add-box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /client/icons/add-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 16 | 17 | -------------------------------------------------------------------------------- /client/icons/add-polygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 11 | 18 | 19 | -------------------------------------------------------------------------------- /client/icons/add-spring.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/icons/axle.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /client/icons/bolt.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /client/icons/polygon.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /client/icons/spring.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Simulo Alpha", 3 | "short_name": "Simulo", 4 | "description": "Free and open-source online 2D physics app", 5 | "start_url": "/", 6 | "display": "standalone", 7 | "icons": [ 8 | { 9 | "src": "media/icon.svg", 10 | "type": "image/svg+xml", 11 | "sizes": "any" 12 | }, 13 | { 14 | "src": "media/icon.png", 15 | "type": "image/png", 16 | "sizes": "512x512" 17 | }, 18 | { 19 | "src": "media/icon_small.png", 20 | "type": "image/png", 21 | "sizes": "256x256" 22 | }, 23 | { 24 | "src": "media/icon_smaller.png", 25 | "type": "image/png", 26 | "sizes": "128x128" 27 | }, 28 | { 29 | "src": "media/maskable_icon_x512.png", 30 | "type": "image/png", 31 | "sizes": "512x512", 32 | "purpose": "maskable" 33 | }, 34 | { 35 | "src": "media/icon_192.png", 36 | "type": "image/png", 37 | "sizes": "192x192" 38 | }, 39 | { 40 | "src": "media/maskable_icon_x192.png", 41 | "type": "image/png", 42 | "sizes": "192x192", 43 | "purpose": "maskable" 44 | }, 45 | { 46 | "src": "media/maskable_icon_x128.png", 47 | "type": "image/png", 48 | "sizes": "128x128", 49 | "purpose": "maskable" 50 | } 51 | ], 52 | "background_color": "#322860", 53 | "theme_color": "#0f1130", 54 | "scope": "/", 55 | "prefer_related_applications": false 56 | } -------------------------------------------------------------------------------- /client/src/Example.ts: -------------------------------------------------------------------------------- 1 | import SimuloPhysicsServer from "./SimuloPhysicsServer"; 2 | import SimuloTheme from "./SimuloTheme"; 3 | const physicsServer = new SimuloPhysicsServer({ 4 | 5 | } as SimuloTheme); 6 | 7 | var cachedObjects: { [key: number]: any } = {}; 8 | var cachedObjectID = -1; 9 | 10 | var worker = new Worker('worker.js'); 11 | 12 | worker.onmessage = async function (event) { 13 | if (event.data.type === 'get') { 14 | if (cachedObjects[event.data.cachedObjectID]) { 15 | try { 16 | worker.postMessage({ 17 | type: 'response', 18 | key: event.data.key, 19 | value: cachedObjects[event.data.cachedObjectID][event.data.key], 20 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 21 | }); 22 | } 23 | catch (e) { 24 | worker.postMessage({ 25 | type: 'response', 26 | key: event.data.key, 27 | value: undefined, 28 | requestID: event.data.requestID, // pass it back so it can identify what request it is responding to 29 | error: e 30 | }); 31 | } 32 | } 33 | else { 34 | worker.postMessage({ 35 | type: 'response', 36 | key: event.data.key, 37 | value: undefined, 38 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 39 | }); 40 | } 41 | } 42 | else if (event.data.type === 'call') { 43 | if (cachedObjects[event.data.cachedObjectID]) { 44 | try { 45 | var returned = cachedObjects[event.data.cachedObjectID][event.data.key](...event.data.args); // this might error if its not a function or doesn't exist, but we're in try-catch and this way it'll send real error to the worker 46 | worker.postMessage({ 47 | type: 'response', 48 | key: event.data.key, 49 | value: returned, 50 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 51 | }); 52 | } 53 | catch (e) { 54 | worker.postMessage({ 55 | type: 'response', 56 | key: event.data.key, 57 | value: undefined, 58 | requestID: event.data.requestID, // pass it back so it can identify what request it is responding to 59 | error: e 60 | }); 61 | } 62 | } 63 | else { 64 | worker.postMessage({ 65 | type: 'response', 66 | key: event.data.key, 67 | value: undefined, 68 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 69 | }); 70 | } 71 | } 72 | else if (event.data.type === 'set') { 73 | //(obj as any)[event.data.key] = event.data.value; 74 | if (cachedObjects[event.data.cachedObjectID]) { 75 | try { 76 | cachedObjects[event.data.cachedObjectID][event.data.key] = event.data.value; 77 | worker.postMessage({ 78 | type: 'response', 79 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 80 | }); 81 | } 82 | catch (e) { 83 | worker.postMessage({ 84 | type: 'response', 85 | requestID: event.data.requestID, // pass it back so it can identify what request it is responding to 86 | error: e 87 | }); 88 | } 89 | } 90 | else { 91 | worker.postMessage({ 92 | type: 'response', 93 | requestID: event.data.requestID, // pass it back so it can identify what request it is responding to 94 | error: 'ReferenceError: object is not defined' 95 | }); 96 | } 97 | } 98 | else if (event.data.type === 'log') { 99 | console.log(event.data.msg); 100 | } 101 | else if (event.data.type === 'getObject') { 102 | var gottenObj = { name: 'joe' }; 103 | if (gottenObj) { 104 | cachedObjectID++; 105 | cachedObjects[cachedObjectID] = gottenObj; 106 | worker.postMessage({ 107 | type: 'response', 108 | value: gottenObj ? true : false, 109 | cachedObjectID: cachedObjectID, 110 | requestID: event.data.requestID // pass it back so it can identify what request it is responding to 111 | }); 112 | } 113 | } 114 | }; 115 | 116 | -------------------------------------------------------------------------------- /client/src/SimuloClient.ts: -------------------------------------------------------------------------------- 1 | // SimuloClient interface is implemented by LocalClient and NetworkClient 2 | 3 | interface SimuloClient { 4 | id: string; 5 | connect(data?: any): void; 6 | disconnect(): void; 7 | on(type: string, callback: Function): void; 8 | off(type: string, callback: Function): void; 9 | /** Emit data over WebRTC */ 10 | emitData(type: string, data: any): void; 11 | /** Emit data over WebSocket */ 12 | emitReliableData(type: string, data: any): void; 13 | } 14 | 15 | export default SimuloClient; -------------------------------------------------------------------------------- /client/src/SimuloClientController/editor.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/client/src/SimuloClientController/editor.ts -------------------------------------------------------------------------------- /client/src/SimuloCreatingObject.ts: -------------------------------------------------------------------------------- 1 | interface SimuloCreatingObject { 2 | x: number; 3 | y: number; 4 | currentX: number; 5 | currentY: number; 6 | color: string; 7 | shape: "circle" | "rectangle" | "polygon" | "edge" | "square" | "select"; 8 | border: string | null; 9 | borderWidth: number | null; 10 | borderScaleWithZoom: boolean; 11 | circleCake?: boolean; // for circles 12 | moving?: boolean; // for select tool 13 | wasStatic?: { [key: number]: boolean }; // for select tool 14 | initialVelocity?: { x: number, y: number }; // for select tool 15 | } 16 | 17 | // extension of creatingobject called creatingpolygon 18 | interface SimuloCreatingPolygon extends SimuloCreatingObject { 19 | vertices: [x: number, y: number][]; 20 | shape: "polygon"; 21 | } 22 | 23 | export default SimuloCreatingObject; 24 | export { SimuloCreatingPolygon, SimuloCreatingObject }; -------------------------------------------------------------------------------- /client/src/SimuloJointData.ts: -------------------------------------------------------------------------------- 1 | import Box2DFactory from "../../node_modules/box2d-wasm/dist/es/entry.js"; 2 | 3 | interface SimuloJointData extends Box2D.b2JointUserData { 4 | id: number; 5 | image: string | null; 6 | line: { color: string, scale_with_zoom: boolean } | null; 7 | width: number; 8 | /** We sort shapes with this for almost everything, including rendering. Newer shapes get a higher Z Depth. At the start of a scene, IDs and Z Depths will be the same, but user interaction can change this. */ 9 | zDepth: number; 10 | anchorA: [x: number, y: number]; 11 | anchorB: [x: number, y: number]; 12 | objectA: number; // simulo object ID (cluster of fixtures) 13 | objectB: number; // simulo object ID (cluster of fixtures) 14 | } 15 | 16 | export default SimuloJointData; -------------------------------------------------------------------------------- /client/src/SimuloLocalClient.ts: -------------------------------------------------------------------------------- 1 | import SimuloClient from "./SimuloClient.js"; 2 | import SimuloServerController from "./SimuloServerController.js"; 3 | 4 | class SimuloLocalClient implements SimuloClient { 5 | listeners: { [key: string]: Function[] } = {}; 6 | serverController: SimuloServerController; 7 | id: string; 8 | connect(): void { 9 | this.emit("connect", null); 10 | this.emit("ready", null); 11 | } 12 | disconnect(): void { 13 | this.emit("disconnect", null); 14 | } 15 | emit(event: string, data: any) { 16 | if (this.listeners[event]) { 17 | this.listeners[event].forEach((listener) => { 18 | listener(data); 19 | }); 20 | } 21 | } 22 | on(event: string, listener: Function) { 23 | if (!this.listeners[event]) { 24 | this.listeners[event] = []; 25 | } 26 | this.listeners[event].push(listener); 27 | } 28 | off(event: string, listener: Function) { 29 | if (this.listeners[event]) { 30 | this.listeners[event] = this.listeners[event].filter((l) => l != listener); 31 | } 32 | } 33 | emitData(type: string, data: any): void { 34 | this.serverController.handleData({ type: type, data: data }, this.id); 35 | } 36 | emitReliableData(type: string, data: any): void { 37 | // TODO: this 38 | } 39 | 40 | constructor(serverController: SimuloServerController, id: string) { 41 | this.serverController = serverController; 42 | this.id = id; 43 | } 44 | 45 | 46 | 47 | } 48 | 49 | export default SimuloLocalClient; -------------------------------------------------------------------------------- /client/src/SimuloNetworkClient/index.ts: -------------------------------------------------------------------------------- 1 | import SimuloClient from "../SimuloClient.js"; 2 | 3 | class SimuloNetworkClient implements SimuloClient { 4 | activeDc: RTCDataChannel | null = null; 5 | listeners: { [key: string]: Function[] } = {}; 6 | id: string; 7 | ws: any | null = null; 8 | localCandidates: RTCIceCandidate[] = []; 9 | 10 | constructor() { 11 | this.localCandidates = []; 12 | this.activeDc = null; 13 | this.listeners = {}; 14 | this.id = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15); // generate a random id 15 | } 16 | 17 | /** 18 | Emit data to the server over WebRTC. Returns true if the data was sent, false if not. 19 | * @example 20 | * networkClient.emitData('playerMove', { x: 0, y: 0 }); 21 | */ 22 | emitData(type: string, data: any) { 23 | if (this.activeDc) { 24 | this.activeDc.send(JSON.stringify({ 25 | type: type, 26 | data: data, 27 | uuid: this.id 28 | })); 29 | return true; 30 | } 31 | return false; 32 | } 33 | 34 | /** Emit data to the server over WebSocket. Returns true if the data was sent, false if not. 35 | * @example 36 | * networkClient.emitReliableData('chatMessage', { message: 'Hello, world!' }); 37 | */ 38 | emitReliableData(type: string, data: any) { 39 | if (this.ws) { 40 | this.ws.send(JSON.stringify({ 41 | type: type, 42 | data: data, 43 | uuid: this.id 44 | })); 45 | return true; 46 | } 47 | return false; 48 | } 49 | 50 | // connect func, we will add jsdoc description 51 | /** 52 | * Connect to the server in both WebRTC and WebSocket. Fires `connect` event when WebSocket connects, and `ready` event when WebRTC connects. 53 | */ 54 | connect(offerSdp: string) { 55 | console.log('network client connecting with offersdp of', offerSdp); 56 | let desc = new RTCSessionDescription({ type: 'offer', sdp: offerSdp }); 57 | let pc = new RTCPeerConnection({ 58 | iceServers: [ 59 | { 60 | urls: "stun:stun.l.google.com:19302", 61 | }, 62 | ], 63 | }); 64 | pc.onicecandidate = (e) => { 65 | if (e.candidate) return; 66 | console.log('omng! ice!') 67 | //alert(pc.localDescription!.sdp); // this is our answer to the offer 68 | console.log('answer sdp:', encodeURIComponent(pc.localDescription!.sdp)); 69 | this.emit("answerSdp", encodeURIComponent(pc.localDescription!.sdp)); 70 | } 71 | pc.oniceconnectionstatechange = (e) => { 72 | console.log('ice connection state change', e); 73 | switch (pc.iceConnectionState) { 74 | case "connected": 75 | console.log('connected'); 76 | break; 77 | case "disconnected": 78 | console.log('disconnected'); 79 | alert('Disconnected from server!'); 80 | break; 81 | case "failed": 82 | console.log('failed'); 83 | // log anything that could be relevant about why ICE failed 84 | console.log('gathering state:', pc.iceGatheringState); 85 | console.log('connection state:', pc.iceConnectionState); 86 | console.log('signaling state:', pc.signalingState); 87 | console.log('local candidates:', this.localCandidates); 88 | // log a big red message with huge text 89 | console.log('%cICE failed!', 'font-size: 50px; color: red;'); 90 | alert('Connection failed! This could be due to router settings, firewall, VPN, etc.'); 91 | break; 92 | case "closed": 93 | console.log('closed'); 94 | break; 95 | } 96 | }; 97 | pc.ondatachannel = (e) => { 98 | let dc = e.channel; 99 | dc.onmessage = (e) => { 100 | try { 101 | var formatted = JSON.parse(e.data); 102 | if ( 103 | formatted.type !== undefined && 104 | formatted.data !== undefined && 105 | formatted.type !== null && 106 | formatted.data !== null 107 | ) { 108 | this.emit("data", { type: formatted.type, data: formatted.data, uuid: this.id }); 109 | } 110 | } catch (e) { 111 | console.log(e); 112 | } 113 | } 114 | dc.onopen = () => { 115 | this.activeDc = dc; 116 | this.emit("ready", this.id); 117 | } 118 | } 119 | pc.setRemoteDescription(desc).then(() => { 120 | pc.createAnswer().then((answer) => { 121 | pc.setLocalDescription(answer); 122 | }); 123 | }); 124 | } 125 | 126 | disconnect() { 127 | if (this.ws) { 128 | this.ws.close(); 129 | } 130 | } 131 | 132 | // on func 133 | /** 134 | * Add an event listener for a specific event type 135 | * @example 136 | * networkClient.on('connect', () => { 137 | * console.log('Connected to WebSocket!'); 138 | * }); 139 | */ 140 | on(type: string, listener: Function) { 141 | if (!this.listeners[type]) { 142 | this.listeners[type] = []; 143 | } 144 | this.listeners[type].push(listener); 145 | } 146 | 147 | // off func 148 | /** 149 | * Remove an event listener for a specific event type 150 | */ 151 | off(type: string, listener: Function) { 152 | if (this.listeners[type]) { 153 | this.listeners[type] = this.listeners[type].filter((l) => { 154 | return l !== listener; 155 | }); 156 | } 157 | } 158 | 159 | emit(type: string, data: any) { 160 | if (this.listeners[type]) { 161 | this.listeners[type].forEach((l) => { 162 | l(data); 163 | }); 164 | } 165 | } 166 | } 167 | 168 | // export the class of SimuloNetworkClient as default 169 | export default SimuloNetworkClient; -------------------------------------------------------------------------------- /client/src/SimuloNetworkServer.ts: -------------------------------------------------------------------------------- 1 | interface Peer { 2 | pc: RTCPeerConnection; 3 | dc: RTCDataChannel; 4 | } 5 | 6 | class SimuloNetworkServer { 7 | listeners: { [key: string]: Function[] } = {}; 8 | private emit(event: string, data: any) { 9 | if (this.listeners[event]) { 10 | this.listeners[event].forEach((listener) => { 11 | listener(data); 12 | }); 13 | } 14 | } 15 | on(event: string, listener: Function) { 16 | if (!this.listeners[event]) { 17 | this.listeners[event] = []; 18 | } 19 | this.listeners[event].push(listener); 20 | } 21 | off(event: string, listener: Function) { 22 | if (this.listeners[event]) { 23 | this.listeners[event] = this.listeners[event].filter((l) => l != listener); 24 | } 25 | } 26 | peers: { [id: string]: Peer } = {}; 27 | connectingPeers: Peer[] = []; 28 | 29 | dcInit(dc: RTCDataChannel, pc: RTCPeerConnection) { 30 | dc.onopen = () => { 31 | //this.dataChannels.push(dc); 32 | this.connectingPeers.push({ pc: pc, dc: dc }); 33 | this.emit("ready", null); 34 | }; 35 | dc.onmessage = (msg) => { 36 | try { 37 | var formatted = JSON.parse(msg.data); 38 | //this.dcIDs[formatted.id] = dc; 39 | // find our peer from the datachannel 40 | if (!this.peers[formatted.uuid]) { 41 | var peer = this.connectingPeers.find((p) => p.dc === dc); 42 | if (peer) { 43 | this.peers[formatted.uuid] = peer; 44 | this.connectingPeers = this.connectingPeers.filter((p) => p !== peer); 45 | } 46 | } 47 | // it should have a type and data. if not, it's not a valid message 48 | if ( 49 | formatted.type !== undefined && 50 | formatted.data !== undefined && 51 | formatted.type !== null && 52 | formatted.data !== null 53 | ) { 54 | //this.emit(formatted.type, formatted.data); 55 | this.emit("data", { formatted: formatted, uuid: formatted.uuid }); // TODO: change this to emit the type. will need heavy changes to ServerController 56 | } 57 | } catch (e) { 58 | console.log(e); 59 | } 60 | }; 61 | } 62 | 63 | offered: RTCPeerConnection[] = []; 64 | 65 | joinCode: string | null = null; 66 | 67 | connect() { 68 | let pc = new RTCPeerConnection({ iceServers: [{ urls: "stun:stun.l.google.com:19302" }] }); 69 | pc.onicecandidate = (e) => { 70 | if (e.candidate) { 71 | console.log('returning because e.candidate is not null, which means we are not done yet since we are still getting candidates'); 72 | return; 73 | }; // ok 74 | //alert(encodeURIComponent(pc.localDescription!.sdp)); // if its null we cry about it 75 | console.log('on ice candidate, the sdp is:', encodeURIComponent(pc.localDescription!.sdp)); 76 | this.joinCode = encodeURIComponent(pc.localDescription!.sdp); 77 | this.emit("joinCode", this.joinCode); 78 | }; 79 | pc.ondatachannel = (e) => { 80 | let dc = e.channel; 81 | this.dcInit(dc, pc); 82 | }; 83 | pc.oniceconnectionstatechange = (e) => { 84 | console.log("ICE connection state changed to " + pc.iceConnectionState); 85 | switch (pc.iceConnectionState) { 86 | case "closed": 87 | case "failed": 88 | case "disconnected": 89 | this.emit("disconnect", 'someone'); 90 | break; 91 | case "connected": 92 | this.emit("connect", 'someone'); 93 | // remove it from the list 94 | this.offered = this.offered.filter((p) => p !== pc); 95 | break; 96 | } 97 | }; 98 | 99 | let dc = pc.createDataChannel("main"); 100 | this.dcInit(dc, pc); 101 | 102 | // create the offer 103 | pc.createOffer().then((offer) => { 104 | pc.setLocalDescription(offer); 105 | /*alert(encodeURIComponent(offer.sdp!)); 106 | console.log('after creating offer, the sdp is:', encodeURIComponent(offer.sdp!));*/ 107 | }); 108 | 109 | //this.connectingPeers.push({ pc: pc, dc: dc }); 110 | this.offered.push(pc); 111 | } 112 | 113 | useAnswerSdp(sdp: string) { 114 | let desc = new RTCSessionDescription({ type: "answer", sdp: sdp }); 115 | //this.pc!.setRemoteDescription(desc); 116 | this.offered.forEach((pc) => { 117 | pc.setRemoteDescription(desc); 118 | }); 119 | } 120 | 121 | sendAll(type: string, data: any) { 122 | Object.keys(this.peers).forEach((key: string) => { 123 | let peer = this.peers[key]; 124 | let dc = peer.dc; 125 | if (dc.readyState != 'open') { 126 | // remove it from the list 127 | delete this.peers[key]; 128 | this.emit("disconnect", null); 129 | console.log('disconnected') 130 | return; 131 | } 132 | try { 133 | dc.send( 134 | JSON.stringify({ 135 | type: type, 136 | data: data, 137 | }) 138 | ); 139 | } catch (e) { 140 | console.error('Error sending message to data channel:', e); 141 | } 142 | }); 143 | } 144 | } 145 | 146 | export default SimuloNetworkServer; -------------------------------------------------------------------------------- /client/src/SimuloObjectData.ts: -------------------------------------------------------------------------------- 1 | import Box2DFactory from "../../node_modules/box2d-wasm/dist/es/entry.js"; 2 | 3 | interface SimuloObjectData { 4 | id: number; 5 | positionOffset: [x: number, y: number]; 6 | angleOffset: number; 7 | /** 8 | * Path to a sound file for collisions. Relative to /assets/sounds/ 9 | */ 10 | name: string | undefined; 11 | sound: string | null; 12 | color: string; 13 | border: string | null; 14 | borderWidth: number | null; 15 | borderScaleWithZoom: boolean; 16 | circleCake?: boolean; 17 | image: string | null; 18 | /** For polygons, this is the full shape used in rendering. In physics, the points from addPolygon are triangulated via earcut. */ 19 | points?: [x: number, y: number][]; 20 | /** We sort shapes with this for almost everything, including rendering. Newer shapes get a higher Z Depth. At the start of a scene, IDs and Z Depths will be the same, but user interaction can change this. */ 21 | zDepth: number; 22 | decomposedParts?: [x: number, y: number][][]; 23 | flipImage?: boolean; 24 | } 25 | 26 | interface SimuloParentData extends Box2D.b2BodyUserData { 27 | // it has a bunch of simuloobjects 28 | objects: { 29 | [id: number]: SimuloObjectData 30 | }; 31 | id: number; 32 | } 33 | 34 | interface SimuloFixtureData extends Box2D.b2FixtureUserData { 35 | id: number; // all we have is an ID, we get the rest from the parent. this prevents duplication of data and having to update it in loads of places 36 | } 37 | 38 | export { SimuloObjectData, SimuloParentData, SimuloFixtureData }; -------------------------------------------------------------------------------- /client/src/SimuloRoom.ts: -------------------------------------------------------------------------------- 1 | // SimuloRoom class has PhysicsServer, NetworkServer and ServerController 2 | import SimuloPhysicsServer from "./SimuloPhysicsServer.js"; 3 | import SimuloTheme from "./SimuloTheme.js"; 4 | import type SimuloStep from "./SimuloStep.js"; 5 | // import SimuloNetworkServer from "./SimuloNetworkServer"; // doesnt exist yet lmao i just dont want IDE errors 6 | 7 | // SimuloRoom is NOT a saved scene, it's an active room that is created when a player loads a scene 8 | 9 | export default class SimuloRoom { 10 | public physicsServer: SimuloPhysicsServer; 11 | public previousStep: SimuloStep | null = null; 12 | // public networkServer: SimuloNetworkServer; 13 | // public controller: SimuloServerController; 14 | //constructor(scene: SimuloScene); 15 | constructor(theme: SimuloTheme) { 16 | this.physicsServer = new SimuloPhysicsServer(theme /* ? theme : scene.theme */); 17 | // this.networkServer = new SimuloNetworkServer(); 18 | // this.controller = new ServerController(); 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /client/src/SimuloShape.ts: -------------------------------------------------------------------------------- 1 | interface SimuloShape { 2 | x: number; 3 | y: number; 4 | type: "circle" | "polygon" | "edge" | "rectangle"; 5 | radius?: number; 6 | /** Measured in radians, angle to rotate the shape by */ 7 | angle: number; 8 | color: string; 9 | border?: string | null; 10 | borderWidth?: number | null; 11 | borderScaleWithZoom?: boolean; 12 | image?: string | null; 13 | imageTransformations?: { 14 | scale: number; 15 | rotate: number; 16 | translate: [x: number, y: number]; 17 | } | null; 18 | zDepth: number; 19 | id: number; 20 | text?: { 21 | color: string; 22 | border?: string | null; 23 | borderWidth?: number | null; 24 | borderScaleWithZoom?: boolean; 25 | // zDepth: number; // Text is always on top or same as parent shape 26 | text: string; 27 | fontSize: number; 28 | fontFamily?: string; 29 | align?: "left" | "center" | "right"; // Default = start 30 | baseline?: "alphabetic" | "top" | "middle" | "bottom"; // Default = alphabetic 31 | } | null; 32 | decomposedParts?: [x: number, y: number][][]; 33 | } 34 | 35 | interface SimuloCircle extends SimuloShape { 36 | type: "circle"; 37 | circleCake: boolean; 38 | } 39 | 40 | interface SimuloPolygon extends SimuloShape { 41 | type: "polygon"; 42 | points: { x: number; y: number }[]; // points is the points of all polygon fixtures so they can be drawn as one 43 | vertices: { x: number, y: number }[]; // vertices is per-fixture 44 | } 45 | 46 | interface SimuloRectangle extends SimuloShape { 47 | type: "rectangle"; 48 | width: number; 49 | height: number; 50 | } 51 | 52 | interface SimuloEdge extends SimuloShape { 53 | type: "edge"; 54 | vertices: { x: number; y: number }[]; 55 | } 56 | 57 | export default SimuloShape; 58 | export { SimuloCircle, SimuloPolygon, SimuloEdge, SimuloShape, SimuloRectangle }; -------------------------------------------------------------------------------- /client/src/SimuloStep.ts: -------------------------------------------------------------------------------- 1 | import SimuloShape from "./SimuloShape.js"; 2 | 3 | interface SimuloStep { 4 | shapes: SimuloShape[]; 5 | background: string; 6 | springs: { 7 | p1: number[], p2: number[], width: number, image: string | null, line: { 8 | color: string; 9 | scale_with_zoom: boolean; 10 | } | null, targetLength: number 11 | }[]; 12 | mouseSprings: { 13 | p1: number[], p2: number[], width: number, image: string | null, line: { 14 | color: string; 15 | scale_with_zoom: boolean; 16 | } | null 17 | }[]; 18 | particles: { 19 | x: number; 20 | y: number; 21 | radius: number; 22 | color: string; 23 | }[]; 24 | } 25 | 26 | export default SimuloStep; -------------------------------------------------------------------------------- /client/src/SimuloText.ts: -------------------------------------------------------------------------------- 1 | interface SimuloText { 2 | x: number; 3 | y: number; 4 | /** Measured in radians, angle to rotate the text by */ 5 | angle?: number; 6 | color: string; 7 | border?: string | null; 8 | borderWidth?: number | null; 9 | borderScaleWithZoom?: boolean; 10 | zDepth: number; 11 | text: string; 12 | fontSize: number; 13 | fontFamily?: string; 14 | align?: "left" | "center" | "right"; // Default = start 15 | baseline?: "alphabetic" | "top" | "middle" | "bottom"; // Default = alphabetic 16 | } 17 | 18 | export default SimuloText; -------------------------------------------------------------------------------- /client/src/SimuloTheme.ts: -------------------------------------------------------------------------------- 1 | interface SimuloTheme { 2 | displayName: string; 3 | author: string; 4 | description: string; 5 | background: string; 6 | ground: { 7 | color: string; 8 | border: string | null; 9 | borderWidth: number | null; 10 | borderScaleWithZoom: boolean; 11 | }; 12 | newObjects: { 13 | color: { 14 | hueMin: number; 15 | hueMax: number; 16 | satMin: number; 17 | satMax: number; 18 | valMin: number; 19 | valMax: number; 20 | alpMin: number; 21 | alpMax: number; 22 | }; 23 | border: string | null; 24 | borderWidth: number | null; 25 | borderScaleWithZoom: boolean; 26 | circleCake: boolean; 27 | springImage: string | null; 28 | axleImage: string | null; 29 | boltImage: string | null; 30 | }; 31 | toolIcons: { [key: string]: string | null }; 32 | systemCursor: boolean; 33 | toolIconSize: number 34 | toolIconOffset: [x: number, y: number]; 35 | person: { 36 | color: string; 37 | border: string | null; 38 | borderWidth: number | null; 39 | borderScaleWithZoom: boolean; 40 | } 41 | }; 42 | 43 | export default SimuloTheme; -------------------------------------------------------------------------------- /client/src/SimuloViewer.ts: -------------------------------------------------------------------------------- 1 | import SimuloShape, { SimuloCircle, SimuloEdge, SimuloPolygon, SimuloRectangle } from "./SimuloShape.js"; 2 | import SimuloText from "./SimuloText.js"; 3 | 4 | /** 5 | * Class that displays SimuloShapes and SimuloTexts on a canvas or other drawing context, typically paired with `SimuloClientController` or a custom controller. 6 | */ 7 | export default interface SimuloViewer { 8 | canvas: HTMLCanvasElement; 9 | cameraOffset: { x: number; y: number; }; 10 | cameraZoom: number; 11 | touchStartElement: any; 12 | isDragging: boolean; 13 | dragStart: { x: number; y: number; }; 14 | dragStart2: { x: number; y: number; }; 15 | /** 16 | * Is the primary mouse or touch input down on the canvas? 17 | */ 18 | pointerDown: boolean; 19 | /** 20 | * Tracks any mouse or touch input down on the canvas, even if it's not the primary input. 21 | */ 22 | mouseTouchDown: number; 23 | initialPinchDistance: number | null; 24 | lastZoom: number; 25 | keysDown: { [key: number]: boolean; }; 26 | previousPinchDistance: number | null; 27 | listeners: { [key: string]: {}; }; 28 | /** 29 | * The loop that calls `draw()`, should not be called manually, just call `draw()` directly instead for that. 30 | */ 31 | loop: () => void; 32 | onPointerMove: (e: any) => void; 33 | onPointerDown: (e: any) => void; 34 | onPointerUp: (e: any) => void; 35 | shapes: SimuloShape[]; 36 | texts: SimuloText[]; 37 | /** 38 | * Returns true if the canvas element has the `.fullscreen` class. 39 | */ 40 | readonly fullscreen: boolean; 41 | /** 42 | * Emit data to listeners. Call `on` to add listeners and `off` to remove them. 43 | */ 44 | emit(event: string, data: any): void; 45 | on(event: string, listener: Function): void; 46 | off(event: string, listener: Function): void; 47 | /** 48 | * Transform a point from screen space to world space 49 | */ 50 | transformPoint(x: number, y: number): { x: any; y: any; }; 51 | /** 52 | * Transform a point from world space to screen space 53 | */ 54 | inverseTransformPoint(x: number, y: number): { x: any; y: any; }; 55 | /** 56 | * Start a loop that calls `draw()` as fast as possible, up to the display's refresh rate. (`window.requestAnimationFrame`) 57 | */ 58 | start(): void; 59 | /** 60 | * Stop the loop that calls `draw()`, can be restarted with `start()` 61 | */ 62 | stop(): void; 63 | resetCamera(): void; 64 | /** 65 | * Adds or removes `.fullscreen` class from the canvas element, which has CSS to make it fill the screen. 66 | */ 67 | setFullscreen(fullscreen: boolean): void; 68 | lineBetweenPoints(x1: number, y1: number, x2: number, y2: number, center?: boolean): { x: number; y: number; angle: number; length: number; }; 69 | /** 70 | * Draw the current state of the world to the canvas or other drawing context. 71 | */ 72 | draw(): void; 73 | 74 | destroy(): void; 75 | } -------------------------------------------------------------------------------- /client/src/css.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.css" { 2 | const value: CSSStyleSheet; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/html.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.html" { 2 | const value: string; 3 | export default value; 4 | } 5 | -------------------------------------------------------------------------------- /client/src/utils.ts: -------------------------------------------------------------------------------- 1 | function getRandomColor(hueMin: number, hueMax: number, satMin: number, satMax: number, valMin: number, valMax: number, alpMin: number, alpMax: number, string: boolean) { 2 | var hue = randomRange(hueMin, hueMax); 3 | var sat = randomRange(satMin, satMax); 4 | var val = randomRange(valMin, valMax); 5 | var alp = randomRange(alpMin, alpMax); 6 | var rgb = hsvToRgb(hue, sat / 100, val / 100); 7 | 8 | // string parameter is optional, it allows you to pick if you want an RGBA CSS string or an array of RGBA values 9 | if (string) { 10 | return 'rgba(' + (rgb[0] * 255) + ', ' + (rgb[1] * 255) + ', ' + (rgb[2] * 255) + ', ' + (alp) + ')'; 11 | } 12 | return [rgb[0] * 255, rgb[1] * 255, rgb[2] * 255, alp]; 13 | } 14 | 15 | function randomRange(min: number, max: number) { 16 | return Math.random() * (max - min) + min; 17 | } 18 | 19 | function hsvToRgb(h: number, s: number, v: number) { 20 | const calculateColor = (n: number, k = (n + h / 60) % 6) => { 21 | const minK = Math.min(k, 4 - k, 1); 22 | const maxK = Math.max(minK, 0); 23 | return v - v * s * maxK; 24 | }; 25 | 26 | const red = calculateColor(5); 27 | const green = calculateColor(3); 28 | const blue = calculateColor(1); 29 | 30 | return [red, green, blue]; 31 | } 32 | 33 | // exports (ESM) 34 | export { getRandomColor, randomRange, hsvToRgb }; -------------------------------------------------------------------------------- /client/src/worker.ts: -------------------------------------------------------------------------------- 1 | var promises: { [key: number]: { resolve: (value: any) => void, reject: (reason?: any) => void, type: 'get' | 'set' | 'getObject' | 'call' } } = {}; 2 | var requestID = -1; 3 | 4 | function getProperty(cachedObjectID: number, key: any) { 5 | return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { 6 | requestID++; 7 | promises[requestID] = { resolve, reject, type: 'get' }; 8 | postMessage({ 9 | type: 'get', 10 | key, 11 | requestID, 12 | cachedObjectID: cachedObjectID, 13 | args: [] 14 | }); 15 | }); 16 | } 17 | function setProperty(cachedObjectID: number, key: any, value: any) { 18 | return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { 19 | requestID++; 20 | promises[requestID] = { resolve, reject, type: 'set' }; 21 | postMessage({ 22 | type: 'set', 23 | key, 24 | requestID, 25 | cachedObjectID: cachedObjectID, 26 | args: [], 27 | value 28 | }); 29 | }); 30 | } 31 | function callMethod(cachedObjectID: number, key: any, args: any[]) { 32 | return new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { 33 | requestID++; 34 | promises[requestID] = { resolve, reject, type: 'call' }; 35 | postMessage({ 36 | type: 'call', 37 | key, 38 | requestID, 39 | cachedObjectID: cachedObjectID, 40 | args 41 | }); 42 | }); 43 | } 44 | 45 | /** Represents an object in the `Scene`. Since scripting runs in a Web Worker, all methods are async. Their promise is only resolved once the server confirms the action. */ 46 | class SimuloRemoteObject { 47 | cachedObjectID: number; 48 | id: number; 49 | async getPosition() { 50 | return getProperty(this.cachedObjectID, 'position') as Promise<[x: number, y: number]>; 51 | } 52 | async setPosition(x: number, y: number) { 53 | return setProperty(this.cachedObjectID, 'position', [x, y]); 54 | } 55 | async getRotation() { 56 | return getProperty(this.cachedObjectID, 'rotation') as Promise; 57 | } 58 | async setRotation(rotation: number) { 59 | return setProperty(this.cachedObjectID, 'rotation', rotation); 60 | } 61 | async getDensity() { 62 | return getProperty(this.cachedObjectID, 'density') as Promise; 63 | } 64 | async setDensity(density: number) { 65 | return setProperty(this.cachedObjectID, 'density', density); 66 | } 67 | async getFriction() { 68 | return getProperty(this.cachedObjectID, 'friction') as Promise; 69 | } 70 | async setFriction(friction: number) { 71 | return setProperty(this.cachedObjectID, 'friction', friction); 72 | } 73 | async getRestitution() { 74 | return getProperty(this.cachedObjectID, 'restitution') as Promise; 75 | } 76 | async setRestitution(restitution: number) { 77 | return setProperty(this.cachedObjectID, 'restitution', restitution); 78 | } 79 | async getBorder() { 80 | return getProperty(this.cachedObjectID, 'border') as Promise; 81 | } 82 | async setBorder(border: boolean) { 83 | return setProperty(this.cachedObjectID, 'border', border); 84 | } 85 | async getBorderWidth() { 86 | return getProperty(this.cachedObjectID, 'borderWidth') as Promise; 87 | } 88 | async setBorderWidth(borderWidth: number) { 89 | return setProperty(this.cachedObjectID, 'borderWidth', borderWidth); 90 | } 91 | async getBorderScaleWithZoom() { 92 | return getProperty(this.cachedObjectID, 'borderScaleWithZoom') as Promise; 93 | } 94 | async setBorderScaleWithZoom(borderScaleWithZoom: boolean) { 95 | return setProperty(this.cachedObjectID, 'borderScaleWithZoom', borderScaleWithZoom); 96 | } 97 | async getCircleCake() { 98 | return getProperty(this.cachedObjectID, 'circleCake') as Promise; 99 | } 100 | async setCircleCake(circleCake: boolean) { 101 | return setProperty(this.cachedObjectID, 'circleCake', circleCake); 102 | } 103 | async getImage() { 104 | return getProperty(this.cachedObjectID, 'image') as Promise; 105 | } 106 | async setImage(image: string | null) { 107 | return setProperty(this.cachedObjectID, 'image', image); 108 | } 109 | async getCollisionSound() { 110 | return getProperty(this.cachedObjectID, 'collisionSound') as Promise; 111 | } 112 | async setCollisionSound(collisionSound: string | null) { 113 | return setProperty(this.cachedObjectID, 'collisionSound', collisionSound); 114 | } 115 | async getColor() { 116 | return getProperty(this.cachedObjectID, 'color') as Promise; 117 | } 118 | async setColor(color: string) { 119 | return setProperty(this.cachedObjectID, 'color', color); 120 | } 121 | async getStatic() { 122 | return getProperty(this.cachedObjectID, 'isStatic') as Promise; 123 | } 124 | async setStatic(isStatic: boolean) { 125 | return setProperty(this.cachedObjectID, 'isStatic', isStatic); 126 | } 127 | async getMass() { 128 | return getProperty(this.cachedObjectID, 'mass') as Promise; 129 | } 130 | async addForce([x, y]: [x: number, y: number]) { 131 | return callMethod(this.cachedObjectID, 'addForce', [[x, y]]); 132 | } 133 | async addImpulse([x, y]: [x: number, y: number]) { 134 | return callMethod(this.cachedObjectID, 'addImpulse', [[x, y]]); 135 | } 136 | async addTorque(torque: number) { 137 | return callMethod(this.cachedObjectID, 'addTorque', [torque]); 138 | } 139 | async addAngularImpulse(impulse: number) { 140 | return callMethod(this.cachedObjectID, 'addAngularImpulse', [impulse]); 141 | } 142 | async destroy() { 143 | return callMethod(this.cachedObjectID, 'destroy', []); 144 | } 145 | 146 | /** Don't create a `SimuloRemoteObject` directly, use `Scene.getObjectByID` instead. */ 147 | constructor(cacheObjectID: number, id: number) { 148 | this.cachedObjectID = cacheObjectID; 149 | this.id = id; 150 | } 151 | } 152 | 153 | /** Global object that represents the active Simulo scene. */ 154 | const Scene = { 155 | /** Returns a `SimuloRemoteObject` that represents the object with the given ID. If no object exists, we return null, no error is thrown. 156 | * 157 | * Example usage: 158 | * ```ts 159 | * var obj = await Scene.getObjectByID(0); 160 | * console.log(await obj.getName()); // Probably prints "Ground" 161 | * ``` 162 | */ 163 | async getObjectByID(id: number) { 164 | var res = await new Promise((resolve: (value: any) => void, reject: (reason?: any) => void) => { 165 | requestID++; 166 | promises[requestID] = { resolve, reject, type: 'getObject' }; 167 | postMessage({ 168 | type: 'getObject', 169 | id, 170 | requestID 171 | }); 172 | }); 173 | // res is a boolean 174 | var exists = res.value as boolean; 175 | var cachedObjectID = res.cachedObjectID as number; 176 | if (exists) { 177 | var obj = new SimuloRemoteObject(cachedObjectID, id); 178 | return obj; 179 | } 180 | else { 181 | return null; 182 | } 183 | } 184 | }; 185 | 186 | onmessage = async function (event) { 187 | if (event.data.type === 'response') { 188 | var promise = promises[event.data.requestID]; 189 | if (promise) { 190 | if (event.data.error) { 191 | promise.reject(event.data.error); 192 | } 193 | else { 194 | if (promises[event.data.requestID].type !== 'getObject') { 195 | promise.resolve(event.data.value); 196 | } 197 | else { 198 | promise.resolve(event.data); 199 | } 200 | } 201 | delete promises[event.data.requestID]; 202 | } 203 | } 204 | else if (event.data.type === 'log') { 205 | console.log(event.data.msg); 206 | } 207 | else if (event.data.type === 'startScript') { 208 | // new function 209 | eval(event.data.value); 210 | } 211 | }; 212 | 213 | 214 | 215 | async function test() { 216 | console.log('getting obj') 217 | var obj = (await Scene.getObjectByID(1)) as SimuloRemoteObject; 218 | console.log('got it'); 219 | console.log('pos: ' + await obj.getPosition()); 220 | } test(); -------------------------------------------------------------------------------- /client/sw.js: -------------------------------------------------------------------------------- 1 | /* 2 | Until this issue is resolved, this Service Worker will be in JS instead of TS. 3 | https://github.com/Microsoft/TypeScript/issues/11781 4 | */ 5 | 6 | const cacheName = 'simulo-1'; 7 | //console.log('Service Worker starting...'); 8 | self.addEventListener('activate', async (event) => { 9 | console.log('Service Worker activated'); 10 | }); 11 | 12 | async function cacheEverything() { 13 | // first, fetch /fileList.txt 14 | const fileList = await fetch('filelist.txt').then((response) => response.text()); 15 | var files = fileList.trim().split('\n'); 16 | return files; 17 | } 18 | 19 | self.addEventListener('install', async (event) => { 20 | var files = await cacheEverything(); 21 | /* 22 | event.waitUntil( 23 | caches.open(cacheName) 24 | .then((cache) => cache.addAll([ 25 | '/Simulo' 26 | ].concat(files))) 27 | ); 28 | console.log('Cached ' + files.length + ' files');*/ 29 | // lets cache individually for debugging 30 | for (let file of files) { 31 | var cache = await caches.open(cacheName) 32 | try { 33 | await cache.add(file); 34 | console.log('Cached ' + file); 35 | } 36 | catch (e) { 37 | console.log('Failed to cache ' + file); 38 | } 39 | } 40 | console.log('Cached ' + files.length + ' files'); 41 | console.log('Service Worker installed!'); 42 | }); 43 | self.addEventListener('fetch', async (event) => { 44 | if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { 45 | console.log('Only-if-cached request for', event.request.url); 46 | return; 47 | } 48 | 49 | /*var match = await caches.match(event.request); 50 | if (match) { 51 | console.log('Cache hit for', event.request.url); 52 | event.respondWith(match); 53 | return; 54 | } 55 | else { 56 | console.log('Cache miss for', event.request.url); 57 | }*/ 58 | event.respondWith( 59 | caches.match(event.request).then((response) => { 60 | if (response) { 61 | console.log('Cache hit for', event.request.url); 62 | return response; 63 | } 64 | else { 65 | console.log('Cache miss for', event.request.url); 66 | // fetch and cache 67 | return fetch(event.request).then((response) => { 68 | if (response.status === 200) { 69 | // cache 70 | var responseClone = response.clone(); 71 | caches.open(cacheName).then((cache) => { 72 | cache.put(event.request, responseClone); 73 | }); 74 | } 75 | return response; 76 | }); 77 | } 78 | }) 79 | ); 80 | }); 81 | 82 | async function update() { 83 | console.log('Updating...'); 84 | // clear all caches 85 | caches.keys().then((names) => { 86 | for (let name of names) { 87 | caches.delete(name); 88 | } 89 | } 90 | ); 91 | // cache everything 92 | var files = await cacheEverything(); 93 | await caches.open(cacheName) 94 | .then((cache) => cache.addAll([ 95 | '/Simulo' 96 | ].concat(files))); 97 | console.log('Update complete!'); 98 | } 99 | /* 100 | onmessage = async function (event) { 101 | console.log('Message received:', event.data); 102 | if (event.data.type === 'update') { 103 | await update(); 104 | postMessage({ key: event.data.key }); 105 | } 106 | console.log('Done!') 107 | };*/ 108 | self.addEventListener('message', async (event) => { 109 | console.log('ServiceWorker Message Handler: Message received:', event.data); 110 | if (event.data.type === 'update') { 111 | await update(); 112 | event.ports[0].postMessage('Successfully updated!'); 113 | } 114 | console.log('ServiceWorker Message Handler: Done!') 115 | }); -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "esnext", 4 | "target": "ES2021", 5 | "esModuleInterop": true, 6 | "sourceMap": true, 7 | "outDir": "../dist", 8 | "rootDir": "../", 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "allowSyntheticDefaultImports": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "dist"] 17 | } 18 | -------------------------------------------------------------------------------- /media/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/banner.png -------------------------------------------------------------------------------- /media/banner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 40 | 42 | 45 | 49 | 53 | 54 | 60 | 70 | 73 | 77 | 81 | 82 | 92 | 93 | 98 | 106 | 109 | 114 | 117 | 120 | 123 | 126 | 129 | 132 | 133 | 139 | 142 | 147 | 152 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /media/icon change.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ->icon change?let me know in a github issue!! 159 | -------------------------------------------------------------------------------- /media/icon change.svg.2023_06_22_21_50_31.3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ->icon change?both palettes will be available asscene themes in-game 157 | -------------------------------------------------------------------------------- /media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon.png -------------------------------------------------------------------------------- /media/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 37 | 39 | 49 | 52 | 56 | 60 | 61 | 62 | 67 | 73 | 77 | 82 | 87 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /media/icon_192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_192.png -------------------------------------------------------------------------------- /media/icon_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_bg.png -------------------------------------------------------------------------------- /media/icon_fg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_fg.png -------------------------------------------------------------------------------- /media/icon_no_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_no_bg.png -------------------------------------------------------------------------------- /media/icon_no_bg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 46 | 49 | 54 | 59 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /media/icon_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_small.png -------------------------------------------------------------------------------- /media/icon_smaller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_smaller.png -------------------------------------------------------------------------------- /media/icon_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_square.png -------------------------------------------------------------------------------- /media/icon_square.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 40 | 42 | 45 | 49 | 53 | 54 | 63 | 64 | 69 | 77 | 81 | 86 | 91 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /media/icon_square_new.svg.2023_06_22_21_50_31.0.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 40 | 42 | 45 | 49 | 53 | 54 | 63 | 64 | 69 | 77 | 81 | 86 | 91 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /media/icon_square_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/icon_square_old.png -------------------------------------------------------------------------------- /media/icon_square_old.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 40 | 42 | 45 | 49 | 53 | 54 | 63 | 64 | 69 | 77 | 80 | 85 | 90 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /media/imulo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/imulo.png -------------------------------------------------------------------------------- /media/imulo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 40 | 42 | 45 | 49 | 53 | 57 | 58 | 67 | 75 | 79 | 80 | 81 | 86 | 94 | 98 | 103 | 108 | 113 | 114 | * 125 | 126 | 127 | -------------------------------------------------------------------------------- /media/limegreen.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 46 | 54 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /media/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/logo.png -------------------------------------------------------------------------------- /media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 37 | 39 | 45 | 55 | 58 | 62 | 66 | 67 | 68 | 73 | 76 | 81 | 84 | 87 | 90 | 93 | 96 | 99 | 100 | 101 | 107 | 111 | 116 | 121 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /media/maskable_icon_x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/maskable_icon_x128.png -------------------------------------------------------------------------------- /media/maskable_icon_x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/maskable_icon_x192.png -------------------------------------------------------------------------------- /media/maskable_icon_x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/media/maskable_icon_x512.png -------------------------------------------------------------------------------- /media/urple.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 39 | 41 | 46 | 54 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /other/box2d-wasm-7.0.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/other/box2d-wasm-7.0.0.tgz -------------------------------------------------------------------------------- /other/tsedition: -------------------------------------------------------------------------------- 1 | // main.js 2 | const obj = { foo: 'bar', baz: 42 }; 3 | const keys = Object.keys(obj); 4 | 5 | const worker = new Worker('worker.js'); 6 | worker.postMessage(keys); 7 | 8 | worker.onmessage = function (event) { 9 | if (event.data.type === 'get') { 10 | 11 | } 12 | }; 13 | 14 | //------------------------------------------------ 15 | 16 | // worker.js 17 | onmessage = function (event) { 18 | const keys = event.data; 19 | const proxy = new Proxy({}, { 20 | get(target, prop) { 21 | return new Promise(resolve => { 22 | postMessage({ type: 'get', key: prop }); 23 | onmessage = function (event) { 24 | if (event.data.type === 'get' && event.data.key === prop) { 25 | resolve(event.data.value); 26 | } 27 | }; 28 | }); 29 | } 30 | }); 31 | postMessage({ type: 'ready' }); 32 | onmessage = function (event) { 33 | if (event.data.type === 'get' && keys.includes(event.data.key)) { 34 | postMessage({ 35 | type: 'response', 36 | key: event.data.key, 37 | value: obj[event.data.key] 38 | }); 39 | } 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simulo", 3 | "version": "0.10.0", 4 | "main": "dist/server/src/index.js", 5 | "scripts": { 6 | "start": "bun server/src/index.ts", 7 | "build": "bun scripts/build.ts", 8 | "dev": "bun scripts/build.ts && bun run server/src/index.ts", 9 | "watch": "bun scripts/watch.ts", 10 | "desktop": "bun scripts/desktop.ts", 11 | "all": "bun scripts/all-pre.ts && bun run scripts/build.ts && node scripts/deploy.js", 12 | "canary": "bun scripts/all-pre.ts && bun run scripts/build.ts && node scripts/deploy.js --canary" 13 | }, 14 | "dependencies": { 15 | "@mdi/svg": "^7.2.96", 16 | "@tabler/icons": "^2.10.0", 17 | "@types/emscripten": "^1.39.6", 18 | "box2d-wasm": "./other/box2d-wasm-7.0.0.tgz", 19 | "chalk": "^5.2.0", 20 | "chokidar": "^3.5.3", 21 | "earcut": "^2.2.4", 22 | "express": "^4.17.2", 23 | "node-datachannel": "^0.4.1", 24 | "node-pre-gyp": "^0.17.0", 25 | "simple-peer": "^9.11.1", 26 | "socket.io": "^4.6.1", 27 | "terminal-link": "^3.0.0", 28 | "tree-kill": "^1.2.2", 29 | "wrtc": "^0.4.7", 30 | "ws": "^8.13.0" 31 | }, 32 | "devDependencies": { 33 | "@types/earcut": "^2.1.1", 34 | "@types/express": "^4.17.17", 35 | "@types/gh-pages": "^3.2.1", 36 | "@types/node": "^20.4.5", 37 | "@types/ws": "^8.5.5", 38 | "bun-types": "^0.7.3", 39 | "gh-pages": "^5.0.0", 40 | "tsup": "^7.1.0", 41 | "tsx": "^3.12.7", 42 | "typescript": "^5.1.6" 43 | }, 44 | "type": "module" 45 | } -------------------------------------------------------------------------------- /scripts/all-pre.ts: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import { packageJson, __dirname, __filename, copyFolderRecursiveSync } from './lib.js'; 3 | 4 | function capitalizeFirstLetter(string: string) { 5 | return string.charAt(0).toUpperCase() + string.slice(1); 6 | } 7 | 8 | var buildInfo = chalk.bold(capitalizeFirstLetter(packageJson.name) + ' v' + packageJson.version + '\n'); 9 | console.log(buildInfo); 10 | 11 | // ask for version to use 12 | var defaultVersion = packageJson.version; 13 | 14 | import readline from 'readline'; 15 | 16 | const rl = readline.createInterface({ 17 | input: process.stdin, 18 | output: process.stdout 19 | }); 20 | 21 | function ask(question: string, defaultValue: string, callback: (answer: string) => void) { 22 | rl.question(question + ' (enter nothing to use ' + defaultValue + ') ', (answer) => { 23 | if (answer == '') { 24 | answer = defaultValue; 25 | } 26 | else if (answer.startsWith('v')) { 27 | answer = answer.slice(1); 28 | } 29 | callback(answer); 30 | }); 31 | } 32 | 33 | import fs from 'fs'; 34 | import path from 'path'; 35 | 36 | ask('What version should be used?', defaultVersion, (version) => { 37 | console.log('Using version ' + version); 38 | packageJson.version = version; 39 | fs.writeFileSync(path.join(__dirname, 'package.json'), JSON.stringify(packageJson, null, 4)); 40 | rl.close(); 41 | // all done 42 | process.exit(0); 43 | }); -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | // this is JS so we can run it directly with node 2 | // for some reason gh-pages doesnt work on bun :/ 3 | 4 | import fs from 'fs'; 5 | import * as url from "url"; 6 | import path from 'path'; 7 | 8 | const __filename = url.fileURLToPath(import.meta.url); 9 | const __dirname = url.fileURLToPath(new URL("../.", import.meta.url)); 10 | const packageJson = JSON.parse(fs.readFileSync(__dirname + 'package.json', 'utf8')); 11 | 12 | import ghpages from 'gh-pages'; 13 | 14 | import chalk from 'chalk'; 15 | 16 | function capitalizeFirstLetter(string) { 17 | return string.charAt(0).toUpperCase() + string.slice(1); 18 | } 19 | 20 | // get canary param if it exists 21 | var canary = false; 22 | if (process.argv.includes('--canary')) { 23 | canary = true; 24 | } 25 | 26 | var buildInfo = chalk.bold('Deploying ' + capitalizeFirstLetter(packageJson.name) + ' v' + packageJson.version + (canary ? ' to Canary' : '') + '...\n'); 27 | console.log(buildInfo); 28 | 29 | var steps = [ 30 | async (stepInfo) => { 31 | console.log(stepInfo, 'Checking for build...'); 32 | if (!fs.existsSync(path.join(__dirname, 'dist'))) { 33 | console.log(chalk.redBright('No build found! Please run `bun run build` first.')); 34 | process.exit(1); 35 | } 36 | }, 37 | // deploy to gh-pages 38 | async (stepInfo) => { 39 | console.log(stepInfo, 'Deploying to GitHub Pages...'); 40 | await new Promise((resolve, reject) => { 41 | ghpages.publish(path.join(__dirname, 'dist'), { 42 | branch: 'gh-pages', 43 | repo: canary ? 'git@github.com:Carroted/Simulo-Canary.git' : undefined, 44 | dotfiles: true, 45 | }, function (err) { 46 | if (err) { 47 | console.log(chalk.redBright('Error deploying to GitHub Pages: ' + err)); 48 | reject(err); 49 | process.exit(1); 50 | } 51 | else { 52 | resolve(null); 53 | } 54 | }); 55 | }); 56 | } 57 | ]; 58 | 59 | // run steps 60 | for (var i = 0; i < steps.length; i++) { 61 | await steps[i]((i + 1) + '/' + steps.length); 62 | } 63 | 64 | 65 | console.log(chalk.greenBright.bold('\nDeployed successfully!') + '\nNote: While changes have been sent to GitHub, it takes up to 10 minutes for them to be visible.'); -------------------------------------------------------------------------------- /scripts/desktop.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import * as url from "url"; 3 | 4 | import path from 'path'; 5 | 6 | import chalk from 'chalk'; 7 | 8 | // import child_process 9 | import { exec } from 'child_process'; 10 | import { packageJson, __dirname, __filename, copyFolderRecursiveSync } from './lib.js'; 11 | 12 | function capitalizeFirstLetter(string: string) { 13 | return string.charAt(0).toUpperCase() + string.slice(1); 14 | } 15 | 16 | var buildInfo = chalk.bold('Packaging ' + capitalizeFirstLetter(packageJson.name) + ' v' + packageJson.version + '...\n'); 17 | console.log(buildInfo); 18 | 19 | var steps = [ 20 | // make sure theres ../Simulo-Desktop 21 | async (stepInfo: string) => { 22 | console.log(stepInfo, 'Checking for ../Simulo-Desktop...'); 23 | if (!fs.existsSync(path.join(__dirname, '..', 'Simulo-Desktop'))) { 24 | console.log(chalk.redBright('No ../Simulo-Desktop found! Please clone it from https://github.com/Carroted/Simulo-Desktop and run `npm i` there.')); 25 | process.exit(1); 26 | } 27 | }, 28 | async (stepInfo: string) => { 29 | console.log(stepInfo, 'Checking for build...'); 30 | if (!fs.existsSync(path.join(__dirname, 'dist'))) { 31 | console.log(chalk.redBright('No build found! Please run `bun run build` first.')); 32 | process.exit(1); 33 | } 34 | }, 35 | // delete static folder there 36 | async (stepInfo: string) => { 37 | console.log(stepInfo, 'Clearing previous build from ../Simulo-Desktop...'); 38 | const staticPath = path.join(__dirname, '..', 'Simulo-Desktop', 'static'); 39 | fs.rmSync(staticPath, { recursive: true }); 40 | }, 41 | // copy dist folder there as static 42 | async (stepInfo: string) => { 43 | console.log(stepInfo, 'Copying build to ../Simulo-Desktop/static...'); 44 | copyFolderRecursiveSync(path.join(__dirname, 'dist'), path.join(__dirname, '..', 'Simulo-Desktop', 'static')); 45 | }, 46 | // set version in simulo-desktop 47 | async (stepInfo: string) => { 48 | console.log(stepInfo, 'Setting version in ../Simulo-Desktop...'); 49 | const packageJsonPath = path.join(__dirname, '..', 'Simulo-Desktop', 'package.json'); 50 | const desktopPackageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); 51 | desktopPackageJson.version = packageJson.version; 52 | fs.writeFileSync(packageJsonPath, JSON.stringify(desktopPackageJson, null, 4)); 53 | }, 54 | // exec `./node_modules/.bin/electron-builder` there 55 | async (stepInfo: string) => { 56 | console.log(stepInfo, 'Packaging with electron-builder...'); 57 | await new Promise((resolve, reject) => { 58 | let p = exec('./node_modules/.bin/electron-builder --linux deb tar.xz', { 59 | cwd: path.join(__dirname, '..', 'Simulo-Desktop') 60 | }, function (err) { 61 | if (err) { 62 | console.log(chalk.redBright('Error packaging with electron-builder: ' + err)); 63 | reject(err); 64 | process.exit(1); 65 | } 66 | else { 67 | resolve(null); 68 | } 69 | }); 70 | p.stdout!.on('data', function (data) { 71 | console.log(data); 72 | }); 73 | p.stderr!.on('data', function (data) { 74 | console.log(data); 75 | }); 76 | }); 77 | } 78 | ]; 79 | 80 | // run steps 81 | for (var i = 0; i < steps.length; i++) { 82 | await steps[i]((i + 1) + '/' + steps.length); 83 | } 84 | 85 | 86 | console.log(chalk.greenBright.bold('\nPackaged successfully!') + '\nSee it in ../Simulo-Desktop/dist/'); -------------------------------------------------------------------------------- /scripts/lib.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | import url from "url"; 4 | 5 | export const __filename = url.fileURLToPath(import.meta.url); 6 | export const __dirname = url.fileURLToPath(new URL("../.", import.meta.url)); 7 | export const packageJson = JSON.parse(fs.readFileSync(__dirname + 'package.json', 'utf8')); 8 | 9 | export function copyFolderRecursiveSync(source: string, target: string) { 10 | let files: string[] = []; 11 | // check if folder needs to be created or integrated 12 | const targetFolder = target; 13 | if (!fs.existsSync(targetFolder)) { 14 | fs.mkdirSync(targetFolder); 15 | } 16 | // copy 17 | if (fs.lstatSync(source).isDirectory()) { 18 | files = fs.readdirSync(source); 19 | files.forEach(function (file) { 20 | const curSource = path.join(source, file); 21 | if (fs.lstatSync(curSource).isDirectory()) { 22 | copyFolderRecursiveSync(curSource, path.join(targetFolder, path.basename(curSource))); 23 | } 24 | else if (fs.lstatSync(curSource).isSymbolicLink()) { 25 | const symlinkFull = fs.readlinkSync(curSource); 26 | fs.symlinkSync(symlinkFull, path.join(targetFolder, path.basename(curSource))); 27 | } 28 | else { 29 | fs.copyFileSync(curSource, path.join(targetFolder, path.basename(curSource))); 30 | } 31 | }); 32 | } 33 | } -------------------------------------------------------------------------------- /scripts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES2022", 4 | "target": "ES2021", 5 | "esModuleInterop": true, 6 | "sourceMap": true, 7 | "rootDir": "./", 8 | "strict": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "resolveJsonModule": true, 12 | "allowSyntheticDefaultImports": true, 13 | "types": ["bun-types"] 14 | }, 15 | "exclude": ["node_modules", "dist"] 16 | } 17 | -------------------------------------------------------------------------------- /scripts/watch.ts: -------------------------------------------------------------------------------- 1 | // this is watch.js, it runs `npm run dev` with chokidar 2 | 3 | import fs from 'fs'; 4 | import * as url from "url"; 5 | import path from 'path'; 6 | import chalk from 'chalk'; 7 | import chokidar from 'chokidar'; 8 | 9 | import WebSocket, { WebSocketServer } from "ws"; 10 | 11 | let devServerSocket = new WebSocketServer({ port: 4614 }); 12 | devServerSocket.on("connection", (socket) => { 13 | console.log("\n" + chalk.greenBright('->') + " Dev WebSocket connected"); 14 | }); 15 | 16 | import { ChildProcess, exec } from 'child_process'; 17 | import { packageJson, __dirname, __filename } from './lib.js'; 18 | // get dev script 19 | var devScript = `bun scripts/build.ts && bun run server/src/index.ts --dev`; 20 | 21 | let child: ChildProcess; 22 | 23 | import kill from 'tree-kill'; 24 | 25 | async function killAsync(pid: number) { 26 | return new Promise((resolve, reject) => { 27 | kill(pid, (err) => { 28 | if (err) { 29 | reject(err); 30 | } 31 | else { 32 | resolve(); 33 | } 34 | }); 35 | }); 36 | } 37 | 38 | async function runDev(staticChangesOnly = false) { 39 | console.log(' │'); 40 | console.log(' ├ Running dev server...'); 41 | if (child) { 42 | //process.kill(); 43 | await killAsync(child.pid!); 44 | console.log(' ├ Killed previous dev server.'); 45 | } 46 | if (!staticChangesOnly) { 47 | child = exec(devScript, { cwd: __dirname }); 48 | } 49 | else { 50 | child = exec('bun server/src/index.ts --dev', { cwd: __dirname }); 51 | } 52 | child.stdout?.on('data', (data) => { 53 | // if it contains "Build complete in", log it, otherwise ignore 54 | if (data.includes('Build complete in')) { 55 | console.log(' ├ ' + chalk.greenBright(data.trim()).trim()); 56 | } 57 | // if it includes "HTTP server started on port", we tell the dev server to reload 58 | else if (data.includes('HTTP server started on port')) { 59 | console.log(' ├ ' + chalk.greenBright(`Server started on http://localhost:4613/`)); 60 | devServerSocket.clients.forEach((client) => { 61 | client.send("refresh"); 62 | }); 63 | console.log(' └ Told dev WebSockets to reload'); 64 | } 65 | }); 66 | child.stderr?.on('data', (data) => { 67 | console.error(chalk.redBright(data.trim()).trim() + '\n'); 68 | }); 69 | } 70 | 71 | console.log(chalk.bold('Starting dev server...')); 72 | runDev(); 73 | 74 | // watch for changes. specifically, we will look at these: 75 | let watchDirs = [ 76 | 'client', 77 | 'server', 78 | 'package.json', 79 | 'media', 80 | 'website' 81 | ]; 82 | 83 | // watch for changes 84 | for (let watchDir of watchDirs) { 85 | /*fs.watch(path.join(__dirname, watchDir), { recursive: true }, (eventType, filename) => { 86 | //console.log(`event type is: ${eventType}`); 87 | if (filename) { 88 | console.log(chalk.yellowBright(`${filename} file changed!`)); 89 | runDev(); 90 | } 91 | });*/ // no linux 😭 so we chokidar instead 92 | 93 | chokidar.watch(path.join(__dirname, watchDir), { ignoreInitial: true }).on('all', (event, pathStr) => { 94 | // make it relative to __dirname 95 | pathStr = path.relative(__dirname, pathStr); 96 | console.log(chalk.bold(`\n${pathStr} changed!`)); 97 | // check if its in media or in client/assets or in client/icons or its client/index.html or its client/index.css. all those are pretty much the only static files in watchDirs 98 | let staticChangesOnly = false; 99 | if (pathStr.startsWith('media') || pathStr.startsWith('client/assets') || pathStr.startsWith('client/icons') || pathStr.startsWith('client/index.html') || pathStr.startsWith('client/index.css')) { 100 | staticChangesOnly = true; 101 | } 102 | if (staticChangesOnly) { 103 | // remove existing file in dist as long as doesnt start with .. 104 | if (!pathStr.startsWith('..')) { 105 | let distPath = path.join(__dirname, 'dist', pathStr); 106 | if (fs.existsSync(distPath)) { 107 | fs.unlinkSync(distPath); 108 | } 109 | // copy file to dist 110 | fs.copyFileSync(path.join(__dirname, pathStr), distPath); 111 | } 112 | else { 113 | console.log('warning, we are somehow watching external files. this is not good') 114 | } 115 | } 116 | runDev(staticChangesOnly); 117 | }); 118 | } -------------------------------------------------------------------------------- /server/src/index.ts: -------------------------------------------------------------------------------- 1 | // Simulo Server 2 | // Node.js backend for Simulo with server-side physics, WebRTC signaling, etc. 3 | 4 | import express from "express"; 5 | import path from "path"; 6 | 7 | import chalk from "chalk"; 8 | 9 | let dirname = 'dist'; 10 | 11 | import fs from "fs"; 12 | 13 | let dev = false; 14 | if (process.argv.includes("--dev")) { 15 | dev = true; 16 | } 17 | 18 | // if it has --dir, set dirname to it 19 | if (process.argv.includes("--dir")) { 20 | let dirIndex = process.argv.indexOf("--dir"); 21 | if (process.argv[dirIndex + 1]) { 22 | dirname = process.argv[dirIndex + 1]; 23 | } 24 | } 25 | 26 | // make absolute 27 | dirname = path.join(process.cwd(), dirname); 28 | 29 | const versionInfo = JSON.parse(fs.readFileSync(path.join(dirname, 'version.json'), 'utf8')); 30 | 31 | console.log(chalk.bold.hex('#99e077')(`Simulo ${dev ? 'Development ' : ''}Server v${versionInfo.version}`)); 32 | 33 | console.log("Bun server for Simulo"); 34 | 35 | // Get log from log.ts 36 | import log from './log.js'; 37 | 38 | log.info("Starting servers...") // Servers take a few seconds to start up, so we'll log this to the console 39 | 40 | const app: any = express(); // TODO: type this 41 | // make http server (esm import) 42 | import * as http from "http"; 43 | const server = http.createServer(); 44 | server.on("request", app); 45 | 46 | if (dev) { 47 | // we will add Cache-Control: no-store, max-age=0 to each response using express middleware: 48 | app.use((req: any, res: any, next: any) => { 49 | res.set("Cache-Control", "no-store, max-age=0"); 50 | next(); 51 | }); 52 | } 53 | 54 | // if / request without dev param and we're in dev mode, redirect to with dev param (keeping existing params) 55 | app.get("/client", (req: any, res: any, next: any) => { 56 | if (dev && (req.query.dev === undefined || req.query.dev === "")) { 57 | let params = "?"; 58 | for (let key in req.query) { 59 | params += key + "=" + req.query[key] + "&"; 60 | } 61 | // add dev param 62 | params += "dev=true"; 63 | // redirect 64 | res.redirect("/client" + params); 65 | } 66 | else { 67 | // next, we static it later 68 | next(); 69 | } 70 | }); 71 | 72 | app.use(express.static(path.join(dirname))); 73 | 74 | var port = 4613; 75 | // override with env var 76 | if (process.env.PORT) { 77 | if (isNaN(parseInt(process.env.PORT))) { 78 | log.error(`Invalid port "${process.env.PORT}"`); 79 | log.exit(1); 80 | } 81 | port = parseInt(process.env.PORT); 82 | } 83 | 84 | server.listen(port, () => { 85 | console.log(chalk.bold.greenBright(`\nHTTP server started on port ${port}!`) + '\nSee it on ' + 'http://localhost:' + port + ' directly'); 86 | }); 87 | 88 | server.on('error', (e: any) => { 89 | if (e.code === 'EADDRINUSE') { 90 | log.error(`Port ${port} for the public server is already in use`, null, `Close other apps using port ${port} or override the port with "export PORT=1234"`); 91 | log.exit(1); 92 | } 93 | else { 94 | log.error(e.message); 95 | } 96 | }); 97 | 98 | -------------------------------------------------------------------------------- /server/src/log.ts: -------------------------------------------------------------------------------- 1 | // log.ts is a nice console.log system 2 | 3 | import chalk, { ChalkInstance } from 'chalk'; 4 | 5 | // Some proxies don't add ::ffff: to IPV4 addresses. To standardize IPs (e.g. for banning), we add it here. 6 | function getIPV6(ip: string) { 7 | // The inconsistency in IP formats is annoying because someone banned on proxy could get around it by connecting directly 8 | 9 | if (ip.includes("::ffff:")) { 10 | return ip; 11 | } else { 12 | // Check if IPV4 13 | if (ip.includes(".")) { 14 | return "::ffff:" + ip; 15 | } 16 | 17 | // IPV6 18 | return ip; 19 | } 20 | } 21 | 22 | // "Proxy-proof" IP from request headers or req.ip (currently only supports Cloudflare) 23 | function getIP(req: any) { 24 | var ip = req.headers['x-forwarded-for'] || req.ip; 25 | var cloudflare = ip != req.ip; 26 | if (cloudflare) { 27 | ip = ip.split(",")[ip.split(",").length - 1]; 28 | } 29 | return { ip: getIPV6(ip), proxy: cloudflare ? "cloudflare" : null }; // Future-proofing for other proxies 30 | } 31 | 32 | // Beautiful Express request logging in color 33 | function response(message: string, req: any, res: any) { 34 | var color: ChalkInstance = chalk.whiteBright; 35 | if (res.statusCode == 200) { 36 | color = chalk.greenBright; 37 | } else if (res.statusCode == 404) { 38 | color = chalk.redBright; 39 | } else if (res.statusCode == 500 || res.statusCode == 301 || res.statusCode == 302) { 40 | color = chalk.yellowBright; 41 | } 42 | var ipInfo = getIP(req); // req.ip unreliable when some proxies are involved 43 | console.log(color(res.statusCode) + ` ${message} | ${ipInfo.ip} ` + (ipInfo.proxy == "cloudflare" ? chalk.hex('#f48121')(`Cloudflare`) : chalk.blueBright(`Direct`))); 44 | } 45 | 46 | // Exit the process with a message 47 | function exit(code: number) { 48 | console.log("\nExited with code " + code); 49 | process.exit(code); 50 | } 51 | 52 | function error(message: string, code?: string | null, tip?: string | null) { 53 | if (tip && code) { 54 | console.error(chalk.bold(chalk.redBright(`\nError[${code}]`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 55 | } 56 | else if (code) { 57 | console.error(chalk.bold(chalk.redBright(`\nError[${code}]`) + `: ${message} `)); 58 | } 59 | else if (tip) { 60 | console.error(chalk.bold(chalk.redBright(`\nError`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 61 | } 62 | else { 63 | console.error(chalk.bold(chalk.redBright(`\nError`) + `: ${message} `)); 64 | } 65 | } 66 | 67 | function warning(message: string, code?: string | null, tip?: string | null) { 68 | if (tip && code) { 69 | console.warn(chalk.bold(chalk.yellowBright(`\nWarning[${code}]`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 70 | } 71 | else if (code) { 72 | console.warn(chalk.bold(chalk.yellowBright(`\nWarning[${code}]`) + `: ${message} `)); 73 | } 74 | else if (tip) { 75 | console.warn(chalk.bold(chalk.yellowBright(`\nWarning`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 76 | } 77 | else { 78 | console.warn(chalk.bold(chalk.yellowBright(`\nWarning`) + `: ${message} `)); 79 | } 80 | } 81 | 82 | function info(message: string, code?: string | null, tip?: string | null) { 83 | if (tip && code) { 84 | console.info(chalk.bold(chalk.blueBright(`\nInfo[${code}]`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 85 | } 86 | else if (code) { 87 | console.info(chalk.bold(chalk.blueBright(`\nInfo[${code}]`) + `: ${message} `)); 88 | } 89 | else if (tip) { 90 | console.info(chalk.bold(chalk.blueBright(`\nInfo`) + `: ${message} `) + `\n ` + chalk.cyanBright(`Tip`) + `: ${tip} `); 91 | } 92 | else { 93 | console.info(chalk.bold(chalk.blueBright(`\nInfo`) + `: ${message} `)); 94 | } 95 | } 96 | 97 | export default { 98 | getIPV6: getIPV6, 99 | getIP: getIP, 100 | response: response, 101 | exit: exit, 102 | error: error, 103 | warning: warning, 104 | warn: warning, // Alias 105 | info: info 106 | }; -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES2022", 4 | "target": "ES2021", 5 | "esModuleInterop": true, 6 | "sourceMap": true, 7 | "outDir": "../dist", 8 | "rootDir": "../", 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "moduleResolution": "node", 12 | "resolveJsonModule": true, 13 | "allowSyntheticDefaultImports": true 14 | }, 15 | "include": ["src/**/*"], 16 | "exclude": ["node_modules", "dist"] 17 | } 18 | -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Black.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-BlackItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Bold.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-BoldItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-ExtraBold.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-ExtraBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-ExtraBoldItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-ExtraLight.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-ExtraLight.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-ExtraLightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-ExtraLightItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Italic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Light.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-LightItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-LightItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Medium.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-MediumItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-MediumItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Regular.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-SemiBold.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-SemiBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-SemiBoldItalic.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-Thin.woff2 -------------------------------------------------------------------------------- /website/assets/fonts/Urbanist-ThinItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/fonts/Urbanist-ThinItalic.woff2 -------------------------------------------------------------------------------- /website/assets/sounds/button_down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/button_down.wav -------------------------------------------------------------------------------- /website/assets/sounds/button_up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/button_up.wav -------------------------------------------------------------------------------- /website/assets/sounds/deny.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/deny.wav -------------------------------------------------------------------------------- /website/assets/sounds/ground.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/ground.wav -------------------------------------------------------------------------------- /website/assets/sounds/impact.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/impact.wav -------------------------------------------------------------------------------- /website/assets/sounds/impact_old.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/impact_old.wav -------------------------------------------------------------------------------- /website/assets/sounds/spawn_down.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/spawn_down.wav -------------------------------------------------------------------------------- /website/assets/sounds/spawn_up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/sounds/spawn_up.wav -------------------------------------------------------------------------------- /website/assets/textures/add_axle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_axle.png -------------------------------------------------------------------------------- /website/assets/textures/add_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_circle.png -------------------------------------------------------------------------------- /website/assets/textures/add_circle_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_circle_old.png -------------------------------------------------------------------------------- /website/assets/textures/add_fixed_joint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_fixed_joint.png -------------------------------------------------------------------------------- /website/assets/textures/add_particle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_particle.png -------------------------------------------------------------------------------- /website/assets/textures/add_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_polygon.png -------------------------------------------------------------------------------- /website/assets/textures/add_polygon_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_polygon_old.png -------------------------------------------------------------------------------- /website/assets/textures/add_rectangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_rectangle.png -------------------------------------------------------------------------------- /website/assets/textures/add_rectangle_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_rectangle_old.png -------------------------------------------------------------------------------- /website/assets/textures/add_spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_spring.png -------------------------------------------------------------------------------- /website/assets/textures/add_spring_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/add_spring_old.png -------------------------------------------------------------------------------- /website/assets/textures/body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/body.png -------------------------------------------------------------------------------- /website/assets/textures/body_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/body_purple.png -------------------------------------------------------------------------------- /website/assets/textures/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/car.png -------------------------------------------------------------------------------- /website/assets/textures/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/cursor.png -------------------------------------------------------------------------------- /website/assets/textures/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/person.png -------------------------------------------------------------------------------- /website/assets/textures/person_purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/person_purple.png -------------------------------------------------------------------------------- /website/assets/textures/select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/select.png -------------------------------------------------------------------------------- /website/assets/textures/spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/spring.png -------------------------------------------------------------------------------- /website/assets/textures/spring.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 36 | 38 | 43 | 48 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /website/assets/textures/tools/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/box.png -------------------------------------------------------------------------------- /website/assets/textures/tools/brush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/brush.png -------------------------------------------------------------------------------- /website/assets/textures/tools/chain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/chain.png -------------------------------------------------------------------------------- /website/assets/textures/tools/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/circle.png -------------------------------------------------------------------------------- /website/assets/textures/tools/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/cut.png -------------------------------------------------------------------------------- /website/assets/textures/tools/drag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/drag.png -------------------------------------------------------------------------------- /website/assets/textures/tools/eraser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/eraser.png -------------------------------------------------------------------------------- /website/assets/textures/tools/fixjoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/fixjoint.png -------------------------------------------------------------------------------- /website/assets/textures/tools/gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/gear.png -------------------------------------------------------------------------------- /website/assets/textures/tools/hinge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/hinge.png -------------------------------------------------------------------------------- /website/assets/textures/tools/laserpen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/laserpen.png -------------------------------------------------------------------------------- /website/assets/textures/tools/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/move.png -------------------------------------------------------------------------------- /website/assets/textures/tools/pan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/pan.png -------------------------------------------------------------------------------- /website/assets/textures/tools/plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/plane.png -------------------------------------------------------------------------------- /website/assets/textures/tools/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/polygon.png -------------------------------------------------------------------------------- /website/assets/textures/tools/rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/rotate.png -------------------------------------------------------------------------------- /website/assets/textures/tools/scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/scale.png -------------------------------------------------------------------------------- /website/assets/textures/tools/sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/sketch.png -------------------------------------------------------------------------------- /website/assets/textures/tools/spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/spring.png -------------------------------------------------------------------------------- /website/assets/textures/tools/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/texture.png -------------------------------------------------------------------------------- /website/assets/textures/tools/thruster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/thruster.png -------------------------------------------------------------------------------- /website/assets/textures/tools/tracer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/tracer.png -------------------------------------------------------------------------------- /website/assets/textures/tools/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/tools/zoom.png -------------------------------------------------------------------------------- /website/assets/textures/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/assets/textures/unknown.png -------------------------------------------------------------------------------- /website/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/bg.png -------------------------------------------------------------------------------- /website/bg_old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/bg_old.png -------------------------------------------------------------------------------- /website/img1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/img1.png -------------------------------------------------------------------------------- /website/img2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/img2.png -------------------------------------------------------------------------------- /website/img3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Carroted/Bimulo/4f27dadc6e6a19b1267049c1b4cd7a2248395147/website/img3.png --------------------------------------------------------------------------------