├── workspace
├── assets
│ ├── models
│ │ ├── bird.glb
│ │ ├── boat.bin
│ │ ├── coin.bin
│ │ ├── coin.jpg
│ │ ├── altar.bin
│ │ ├── altar.png
│ │ ├── button.glb
│ │ ├── chicken.bin
│ │ ├── chicken.png
│ │ ├── grass.bin
│ │ ├── panda.glb
│ │ ├── rock-001.bin
│ │ ├── rock-002.bin
│ │ ├── tree-001.bin
│ │ ├── tree-002.bin
│ │ ├── tree-003.bin
│ │ ├── tree-004.bin
│ │ ├── trunk-001.bin
│ │ ├── trunk-002.bin
│ │ ├── button.bg.001.glb
│ │ ├── button.bg.002.glb
│ │ ├── button.bg.003.glb
│ │ ├── button.fg.001.glb
│ │ ├── button.fg.002.glb
│ │ └── button.fg.003.glb
│ ├── sounds
│ │ ├── hit.wav
│ │ └── SuperHero_original.ogg
│ ├── src
│ │ └── colors.xcf
│ ├── textures
│ │ ├── grass.png
│ │ ├── hand.png
│ │ ├── play.png
│ │ ├── vrum.png
│ │ ├── credits.png
│ │ ├── sintel.mp4
│ │ ├── heightmap3.png
│ │ ├── spe_bubble.png
│ │ ├── spe_bullet.png
│ │ ├── spe_cloud.png
│ │ ├── spe_flames.jpg
│ │ ├── spe_spark.png
│ │ ├── spe_star.png
│ │ ├── vrum-text.png
│ │ ├── spe_bullet2.png
│ │ ├── spe_cloudSml.png
│ │ ├── waternormals.jpg
│ │ ├── chicken_black.jpeg
│ │ ├── spe_shockwave.png
│ │ ├── spe_sprite-1x4.jpg
│ │ ├── spe_sprite-2x2.jpg
│ │ ├── spe_sprite-3x2.jpg
│ │ ├── spe_sprite-3x3.jpg
│ │ ├── spe_sprite-4x1.jpg
│ │ ├── vrum-screenshot.png
│ │ ├── spe_smokeparticle.png
│ │ ├── spe_sprite-flame.jpg
│ │ ├── spe_sprite-flame2.jpg
│ │ ├── spe_sprite-smoke.jpg
│ │ ├── black-faded-border.png
│ │ ├── spe_sprite-explosion.png
│ │ └── spe_sprite-explosion2.png
│ ├── fonts
│ │ ├── luckiest-guy.eot
│ │ ├── luckiest-guy.ttf
│ │ ├── luckiest-guy.woff
│ │ └── luckiest-guy.woff2
│ ├── terrains
│ │ └── terrain.json
│ ├── shaders
│ │ ├── basic_shader2.json
│ │ ├── basic_shader.json
│ │ └── dissolve_shader.json
│ ├── particles
│ │ ├── hit.json
│ │ ├── basic.json
│ │ ├── fire-small.json
│ │ ├── fireflies.json
│ │ ├── bubbles.json
│ │ ├── defaults.json
│ │ └── particle.json
│ └── graffiti
│ │ └── majestic-frog-cover.json
└── games
│ ├── project
│ ├── assets
│ │ ├── vrum.png
│ │ ├── favicon.ico
│ │ ├── luckiest-guy.eot
│ │ ├── luckiest-guy.ttf
│ │ ├── luckiest-guy.woff
│ │ └── luckiest-guy.woff2
│ ├── index.html
│ └── game.js
│ ├── test
│ ├── main
│ │ ├── CameraTest.js
│ │ ├── SceneLoaderTest.js
│ │ ├── index.html
│ │ ├── Scene2.js
│ │ ├── Scene3.js
│ │ └── Main.js
│ ├── platformer
│ │ ├── Platformer.js
│ │ ├── StatsPanel.js
│ │ ├── index.html
│ │ └── MainScene.js
│ ├── gamepad-api
│ │ ├── index.html
│ │ └── Gamepad.js
│ ├── scene-setup
│ │ └── index.html
│ ├── networking
│ │ ├── index.html
│ │ └── Networking.js
│ ├── threejs_benchmark.html
│ └── index.html
│ ├── controller2
│ ├── style.css
│ ├── index.html
│ ├── game.js
│ ├── LandingScene.js
│ └── ControllerScene.js
│ ├── model-viewer
│ ├── main.js
│ ├── utils.js
│ ├── index.html
│ └── scene.js
│ ├── scene-editor
│ ├── game.js
│ └── index.html
│ ├── controller
│ ├── style.css
│ ├── index.html
│ └── game.js
│ ├── json-editor
│ ├── index.html
│ └── game.js
│ └── sandbox
│ └── http.js
├── tutorials
├── NETWORKING.md
├── BLENDER.md
└── DISTRIBUTE.md
├── .gitignore
├── src
├── extras
│ ├── controls
│ │ ├── RTSCamera2.js
│ │ ├── RTSCamera.js
│ │ └── RayScanner.js
│ ├── CyclicArray.js
│ ├── ShaderLib.js
│ ├── scenes
│ │ ├── LoadingScene.js
│ │ ├── VideoScene.js
│ │ └── AddsScene.js
│ ├── PolyfillRenderer.js
│ ├── Playlist.js
│ ├── VideoRecorderManager.js
│ ├── AfterEffects.js
│ ├── RStatsManager.js
│ ├── Modifiers.js
│ ├── ShaderMaterial.js
│ ├── StatsManager.js
│ ├── jnorthpole.js
│ └── HighScoreManager.js
├── engine
│ ├── Hodler.js
│ ├── RenderManager.js
│ ├── Scene.js
│ ├── Engine.js
│ ├── InputManager.js
│ └── Config.js
├── tools
│ ├── help.js
│ ├── dependencies.dist.js
│ ├── newGame.js
│ ├── common.js
│ ├── build.js
│ └── publish.js
├── objects
│ ├── Starfield.js
│ ├── SkyBox.js
│ ├── Mirror.js
│ ├── BaseParticle.js
│ ├── Tree.js
│ ├── Water.js
│ ├── SpotLight.js
│ ├── BaseText.js
│ ├── Sky.js
│ ├── Terrain.js
│ └── Button3D.js
└── vendor
│ ├── rStats.css
│ └── threex.rendererstats.js
├── package.json
└── index.html
/workspace/assets/models/bird.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/bird.glb
--------------------------------------------------------------------------------
/workspace/assets/models/boat.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/boat.bin
--------------------------------------------------------------------------------
/workspace/assets/models/coin.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/coin.bin
--------------------------------------------------------------------------------
/workspace/assets/models/coin.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/coin.jpg
--------------------------------------------------------------------------------
/workspace/assets/sounds/hit.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/sounds/hit.wav
--------------------------------------------------------------------------------
/workspace/assets/src/colors.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/src/colors.xcf
--------------------------------------------------------------------------------
/workspace/assets/models/altar.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/altar.bin
--------------------------------------------------------------------------------
/workspace/assets/models/altar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/altar.png
--------------------------------------------------------------------------------
/workspace/assets/models/button.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.glb
--------------------------------------------------------------------------------
/workspace/assets/models/chicken.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/chicken.bin
--------------------------------------------------------------------------------
/workspace/assets/models/chicken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/chicken.png
--------------------------------------------------------------------------------
/workspace/assets/models/grass.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/grass.bin
--------------------------------------------------------------------------------
/workspace/assets/models/panda.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/panda.glb
--------------------------------------------------------------------------------
/workspace/assets/textures/grass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/grass.png
--------------------------------------------------------------------------------
/workspace/assets/textures/hand.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/hand.png
--------------------------------------------------------------------------------
/workspace/assets/textures/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/play.png
--------------------------------------------------------------------------------
/workspace/assets/textures/vrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/vrum.png
--------------------------------------------------------------------------------
/workspace/assets/models/rock-001.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/rock-001.bin
--------------------------------------------------------------------------------
/workspace/assets/models/rock-002.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/rock-002.bin
--------------------------------------------------------------------------------
/workspace/assets/models/tree-001.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/tree-001.bin
--------------------------------------------------------------------------------
/workspace/assets/models/tree-002.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/tree-002.bin
--------------------------------------------------------------------------------
/workspace/assets/models/tree-003.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/tree-003.bin
--------------------------------------------------------------------------------
/workspace/assets/models/tree-004.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/tree-004.bin
--------------------------------------------------------------------------------
/workspace/assets/models/trunk-001.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/trunk-001.bin
--------------------------------------------------------------------------------
/workspace/assets/models/trunk-002.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/trunk-002.bin
--------------------------------------------------------------------------------
/workspace/assets/textures/credits.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/credits.png
--------------------------------------------------------------------------------
/workspace/assets/textures/sintel.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/sintel.mp4
--------------------------------------------------------------------------------
/workspace/assets/fonts/luckiest-guy.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/fonts/luckiest-guy.eot
--------------------------------------------------------------------------------
/workspace/assets/fonts/luckiest-guy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/fonts/luckiest-guy.ttf
--------------------------------------------------------------------------------
/workspace/assets/fonts/luckiest-guy.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/fonts/luckiest-guy.woff
--------------------------------------------------------------------------------
/workspace/assets/textures/heightmap3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/heightmap3.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_bubble.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_bubble.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_bullet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_bullet.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_cloud.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_flames.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_flames.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_spark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_spark.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_star.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_star.png
--------------------------------------------------------------------------------
/workspace/assets/textures/vrum-text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/vrum-text.png
--------------------------------------------------------------------------------
/workspace/games/project/assets/vrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/vrum.png
--------------------------------------------------------------------------------
/workspace/assets/fonts/luckiest-guy.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/fonts/luckiest-guy.woff2
--------------------------------------------------------------------------------
/workspace/assets/models/button.bg.001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.bg.001.glb
--------------------------------------------------------------------------------
/workspace/assets/models/button.bg.002.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.bg.002.glb
--------------------------------------------------------------------------------
/workspace/assets/models/button.bg.003.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.bg.003.glb
--------------------------------------------------------------------------------
/workspace/assets/models/button.fg.001.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.fg.001.glb
--------------------------------------------------------------------------------
/workspace/assets/models/button.fg.002.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.fg.002.glb
--------------------------------------------------------------------------------
/workspace/assets/models/button.fg.003.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/models/button.fg.003.glb
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_bullet2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_bullet2.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_cloudSml.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_cloudSml.png
--------------------------------------------------------------------------------
/workspace/assets/textures/waternormals.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/waternormals.jpg
--------------------------------------------------------------------------------
/workspace/games/project/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/favicon.ico
--------------------------------------------------------------------------------
/workspace/assets/textures/chicken_black.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/chicken_black.jpeg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_shockwave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_shockwave.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-1x4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-1x4.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-2x2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-2x2.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-3x2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-3x2.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-3x3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-3x3.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-4x1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-4x1.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/vrum-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/vrum-screenshot.png
--------------------------------------------------------------------------------
/workspace/assets/sounds/SuperHero_original.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/sounds/SuperHero_original.ogg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_smokeparticle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_smokeparticle.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-flame.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-flame.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-flame2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-flame2.jpg
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-smoke.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-smoke.jpg
--------------------------------------------------------------------------------
/workspace/games/project/assets/luckiest-guy.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/luckiest-guy.eot
--------------------------------------------------------------------------------
/workspace/games/project/assets/luckiest-guy.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/luckiest-guy.ttf
--------------------------------------------------------------------------------
/workspace/assets/textures/black-faded-border.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/black-faded-border.png
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-explosion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-explosion.png
--------------------------------------------------------------------------------
/workspace/games/project/assets/luckiest-guy.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/luckiest-guy.woff
--------------------------------------------------------------------------------
/workspace/games/project/assets/luckiest-guy.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/games/project/assets/luckiest-guy.woff2
--------------------------------------------------------------------------------
/workspace/assets/textures/spe_sprite-explosion2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mess110/vrum/HEAD/workspace/assets/textures/spe_sprite-explosion2.png
--------------------------------------------------------------------------------
/tutorials/NETWORKING.md:
--------------------------------------------------------------------------------
1 | # Networking
2 |
3 | 1. Explain how it works
4 | socket.io vs peer2peer
5 |
6 | 2. Give an example
7 |
8 | 3. Talk about game architectures
9 |
--------------------------------------------------------------------------------
/workspace/games/test/main/CameraTest.js:
--------------------------------------------------------------------------------
1 | class CameraTest extends Scene {
2 | init(options) {
3 | this.add(Utils.box())
4 | }
5 |
6 | doKeyboardEvent(event) {
7 | switchScene(event)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/workspace/games/test/platformer/Platformer.js:
--------------------------------------------------------------------------------
1 | Config.instance.engine.debug = true
2 | Config.instance.window.showStatsOnStart = true
3 | Config.instance.camera.fov = 100
4 | Config.instance.camera.type = 'ortographic'
5 |
6 | Engine.start(new MainScene())
7 |
--------------------------------------------------------------------------------
/workspace/assets/terrains/terrain.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "terrain",
3 | "width": 10,
4 | "height": 10,
5 | "scale": 20,
6 | "texture": {
7 | "libPath": "/workspace/assets/textures/grass.png",
8 | "destPath": "grass.png"
9 | },
10 | "heightmap": {
11 | "libPath": "/workspace/assets/textures/heightmap3.png",
12 | "destPath": "heightmap3.png"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | dist/
3 | tmp/
4 | yarn-error.log
5 |
6 | vrum.js
7 | vrum.min.js
8 |
9 | cert.pem
10 | key.pem
11 | workspace/assets/models/*.blend
12 | workspace/assets/models/*.blend1
13 | workspace/assets/models/*.blend2
14 | workspace/assets/models/*-preview.*
15 | workspace/assets/models/*.tar.gz
16 | workspace/assets/models/toexport
17 | workspace/assets/models/LICENSE
18 |
19 | workspace/assets/**/*.glb
20 |
--------------------------------------------------------------------------------
/workspace/games/controller2/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden;
3 | background-color: #000;
4 | }
5 |
6 | canvas#vrum-dom {
7 | width: 100%;
8 | height: 100%;
9 | }
10 |
11 | .container {
12 | display: flex;
13 | justify-content: center;
14 | align-items: center;
15 | position: absolute;
16 | width: 100%;
17 | height: 100%;
18 | pointer-events: none;
19 | }
20 |
--------------------------------------------------------------------------------
/src/extras/controls/RTSCamera2.js:
--------------------------------------------------------------------------------
1 | // https://github.com/yomotsu/camera-controls
2 | class RTSCamera2 {
3 | constructor() {
4 | this.touch = Utils.isMobileOrTablet()
5 |
6 | CameraControls.install( { THREE: THREE } );
7 | const cameraControls = new CameraControls(Hodler.get('camera'), Hodler.get('renderer').domElement);
8 | this.cameraControls = cameraControls
9 | }
10 |
11 | tick(tpf) {
12 | this.cameraControls.update(tpf);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/workspace/games/test/platformer/StatsPanel.js:
--------------------------------------------------------------------------------
1 | class StatsPanel extends THREE.Object3D {
2 | constructor() {
3 | super()
4 |
5 | var text = new BaseText({
6 | text: 'hello', fillStyle: 'blue', align: 'center',
7 | canvasW: 1024, canvasH: 1024,
8 | font: '128px luckiest-guy'})
9 | text.position.set(0, 0, 4)
10 | this.text = text
11 | this.add(text)
12 |
13 | this.position.set(5, 5, 0)
14 | }
15 |
16 | setText(s) {
17 | this.text.setText(s.toFixed(2))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/engine/Hodler.js:
--------------------------------------------------------------------------------
1 | class Hodler {
2 | constructor() {
3 | this.data = {}
4 | }
5 |
6 | add(key, value) {
7 | this.data[key] = value
8 | }
9 |
10 | get(key) {
11 | return this.data[key]
12 | }
13 |
14 | has(key) {
15 | return !isBlank(this.get(key))
16 | }
17 |
18 | static add(key, value) {
19 | Hodler.instance.add(key, value)
20 | }
21 |
22 | static get(key) {
23 | return Hodler.instance.get(key)
24 | }
25 |
26 | static has(key) {
27 | return Hodler.instance.has(key)
28 | }
29 | }
30 |
31 | Hodler.instance = new Hodler()
32 |
--------------------------------------------------------------------------------
/workspace/games/test/main/SceneLoaderTest.js:
--------------------------------------------------------------------------------
1 | class SceneLoaderTest extends Scene {
2 | init(options) {
3 | resetCamPosition()
4 |
5 | let json = AssetManager.get('boat-scene.json')
6 | let sceneLoader = new SceneLoader(json)
7 |
8 | AssetManager.loadAssets(sceneLoader.getAssets(), () => {
9 | sceneLoader.addToScene()
10 | })
11 | }
12 |
13 | tick(tpf) {}
14 |
15 | doKeyboardEvent(event) {
16 | switchScene(event)
17 | if (event.type == 'keydown' && event.which == 32) {
18 | Engine.switch(Hodler.get('scene1'))
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/tools/help.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const colors = require('colors');
4 |
5 | console.log(`
6 | Example usage:
7 |
8 | yarn [command]
9 |
10 | Commands:
11 |
12 | * h - prints this help
13 | * build - prepares vrum.js and vrum.min.js
14 |
15 | * http - starts a http server
16 | * https - starts a https server. requires self signed certificates
17 | * genkey - generates https self signed certificates
18 |
19 | * new_game - create a new game
20 | * dist:exe - compiles a game to linux/mac/windows executable
21 | * dist:web - publish a repo with gh-pages
22 | `)
23 |
--------------------------------------------------------------------------------
/workspace/assets/shaders/basic_shader2.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "shader",
3 | "uniforms": "{ time: { type: 'f', value: 0 }, resolution: { type: 'v2', value: new THREE.Vector2() } }",
4 | "fragment": "uniform float time;\nvarying vec2 vUv;\n\nvoid main() {\n vec2 position = -1.0 + 2.0 * vUv;\n\n float red = abs(sin(position.x * position.y + time / 5.0));\n float green = abs(sin(position.x * position.y + time / 4.0));\n float blue = abs(sin(position.x * position.y + time / 3.0 ));\n gl_FragColor = vec4(red, green, blue, 1.0);\n}",
5 | "vertex": "varying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}",
6 | "textures": []
7 | }
8 |
--------------------------------------------------------------------------------
/workspace/games/model-viewer/main.js:
--------------------------------------------------------------------------------
1 | Config.instance.window.showStatsOnStart = true
2 | Config.instance.engine.debug = true
3 |
4 | Persist.defaultJson('lastModels', [
5 | '/workspace/assets/models/chicken.gltf',
6 | '/workspace/assets/models/panda.glb',
7 | '/workspace/assets/models/button.glb',
8 | ])
9 | updateLastModels()
10 | stopPropagation()
11 |
12 | let mainScene = new MainScene()
13 | Hodler.add('mainScene', mainScene)
14 |
15 | let loadingScene = new LoadingScene(mainScene, [
16 | { type: 'image', path: '/workspace/assets/textures/vrum.png' },
17 | ])
18 |
19 | Engine.start(loadingScene)
20 |
21 | let camera = Hodler.get('camera');
22 | camera.position.set(0, 4, 10)
23 | camera.lookAt(new THREE.Vector3(0,0,0))
24 |
--------------------------------------------------------------------------------
/workspace/games/controller2/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | vrum.js controller
10 |
11 |
12 |
13 |
14 |
15 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/objects/Starfield.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Example usage:
3 | *
4 | * let starfield = new Starfield()
5 | * this.add(starfield)
6 | */
7 | class Starfield extends THREE.Points {
8 | constructor() {
9 | //This will add a starfield to the background of a scene
10 | var starsGeometry = new THREE.Geometry();
11 |
12 | for ( var i = 0; i < 10000; i ++ ) {
13 |
14 | var star = new THREE.Vector3();
15 | star.x = THREE.Math.randFloatSpread( 2000 );
16 | star.y = THREE.Math.randFloatSpread( 2000 );
17 | star.z = THREE.Math.randFloatSpread( 2000 );
18 |
19 | starsGeometry.vertices.push( star );
20 | }
21 |
22 | var starsMaterial = new THREE.PointsMaterial( { color: 0xFAFAD2 } );
23 |
24 | super(starsGeometry, starsMaterial)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/workspace/games/controller2/game.js:
--------------------------------------------------------------------------------
1 | // Persist.set('username', this.value)
2 |
3 | MeshNetwork.instance = new MeshNetwork()
4 | Utils.orientation('landscape')
5 | Persist.default('username', 'player')
6 |
7 | let controllerScene = new ControllerScene()
8 | let landingScene = new LandingScene()
9 | let roomId = MeshNetwork.getRoomId()
10 | let vrumKey = Utils.guid()
11 | let username = Persist.get('username')
12 |
13 | let startScene
14 | if (isBlank(roomId)) {
15 | startScene = landingScene
16 | } else {
17 | startScene = controllerScene
18 | }
19 |
20 | Engine.start(startScene, [
21 | { type: 'font', path: '/workspace/assets/fonts/luckiest-guy' },
22 |
23 | { type: 'model', path: '/workspace/assets/models/button.bg.001.glb' },
24 | { type: 'model', path: '/workspace/assets/models/button.fg.001.glb' },
25 | ])
26 |
--------------------------------------------------------------------------------
/workspace/games/project/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | vrum.js engine
10 |
14 |
15 |
16 |
17 |
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/extras/CyclicArray.js:
--------------------------------------------------------------------------------
1 | // Used for next() and prev()
2 | //
3 | // a = [1, 2, 3]
4 | // ca = a.toCyclicArray()
5 | // ca.next()
6 | //
7 | class CyclicArray {
8 | constructor(items) {
9 | if (isBlank(items)) { items = [] }
10 | this.items = items
11 | this.index = 0
12 | }
13 |
14 | get() {
15 | return this.items[this.index]
16 | }
17 |
18 | setIndexByValue(item) {
19 | this.index = this.items.indexOf(item)
20 | if (this.index < 0) {
21 | console.warn('did not find item in CyclicArray')
22 | this.index = 0
23 | }
24 | }
25 |
26 | next() {
27 | this.index += 1
28 | if (this.index > (this.items.size() - 1)) { this.index = 0 }
29 | return this.get()
30 | }
31 |
32 | prev() {
33 | this.index -= 1
34 | if (this.index < 0) { this.index = this.items.size() - 1 }
35 | return this.get()
36 | }
37 |
38 | size() {
39 | return this.items.size()
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/workspace/games/scene-editor/game.js:
--------------------------------------------------------------------------------
1 | Config.instance.window.showStatsOnStart = true
2 | Config.instance.engine.debug = true
3 |
4 | function readSingleFile(e) {
5 | var file = e.target.files[0];
6 | if (!file) {
7 | return;
8 | }
9 | var reader = new FileReader();
10 | reader.onload = function(e) {
11 | let contents = e.target.result;
12 | let json = JSON.parse(contents)
13 | let cinematic = new SceneLoader(json)
14 | Hodler.add('cinematic', cinematic)
15 |
16 | Engine.switch(new GameScene(), cinematic.getAssets())
17 |
18 | };
19 | reader.readAsText(file);
20 | }
21 |
22 | document.querySelector('#scene-input')
23 | .addEventListener('change', readSingleFile, false);
24 |
25 | Hodler.add('cinematic', new SceneLoader({
26 | assets: [
27 | { type: 'font', path: '/workspace/assets/fonts/luckiest-guy' },
28 | ]
29 | }))
30 |
31 | Engine.start(new GameScene(), Hodler.get('cinematic').getAssets())
32 |
--------------------------------------------------------------------------------
/workspace/games/test/gamepad-api/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | gamepad
10 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/workspace/games/test/scene-setup/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | scene setup
10 |
14 |
15 |
16 |
17 |
18 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/workspace/assets/shaders/basic_shader.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "shader",
3 | "tick": "(tpf) => { this.uniforms.time.value += tpf * 2 }",
4 | "uniforms": ["{ time: { type: 'f', value: 0 }, resolution: { type: 'v2', value: new THREE.Vector2() } }"],
5 | "fragment": [
6 | "uniform float time;",
7 | "varying vec2 vUv;",
8 | "",
9 | "void main() {",
10 | " vec2 position = -1.0 + 2.0 * vUv;",
11 | "",
12 | " float red = abs(sin(position.x * position.y + time / 5.0));",
13 | " float green = abs(sin(position.x * position.y + time / 4.0));",
14 | " float blue = abs(sin(position.x * position.y + time / 3.0 ));",
15 | " gl_FragColor = vec4(red, green, blue, 1.0);",
16 | "}"
17 | ],
18 | "vertex": [
19 | "varying vec2 vUv;",
20 | "",
21 | "void main() {",
22 | " vUv = uv;",
23 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
24 | "}"
25 | ],
26 | "textures": []
27 | }
28 |
--------------------------------------------------------------------------------
/workspace/games/project/game.js:
--------------------------------------------------------------------------------
1 | class GameScene extends Scene {
2 | init(options) {
3 | let camera = this.getCamera()
4 | camera.position.set(0, 0, 10)
5 | camera.lookAt(new THREE.Vector3(0, 0, 0))
6 |
7 | this.model = Utils.plane({ map: 'vrum.png', width: 6.4, height: 3.65 })
8 | this.add(this.model)
9 | }
10 |
11 | tick(tpf) {
12 | this.model.rotation.x += tpf / 2
13 | this.model.rotation.y += tpf / 2
14 | }
15 |
16 | doMouseEvent(event, raycaster) {
17 | console.log(`${event.type} ${event.which} ${event.x}:${event.y} ${event.wheelDelta}`)
18 | }
19 |
20 | doKeyboardEvent(event) {
21 | console.log(`${event.type} ${event.code} (${event.which})`)
22 | }
23 |
24 | doGamepadEvent(event) {
25 | // console.log(event.type)
26 | }
27 | }
28 |
29 | let gameScene = new GameScene()
30 |
31 | Engine.start(gameScene, [
32 | { type: 'font', path: 'assets/luckiest-guy' },
33 | { type: 'image', path: 'assets/vrum.png' },
34 | ])
35 |
--------------------------------------------------------------------------------
/src/objects/SkyBox.js:
--------------------------------------------------------------------------------
1 | // this.skyBox = new SkyBox(
2 | // [
3 | // '/workspace/assets/px.jpg',
4 | // '/workspace/assets/nx.jpg',
5 | // '/workspace/assets/py.jpg',
6 | // '/workspace/assets/ny.jpg',
7 | // '/workspace/assets/pz.jpg',
8 | // '/workspace/assets/nz.jpg',
9 | // ]
10 | // )
11 | // this.add(this.skyBox)
12 | class SkyBox extends THREE.Mesh {
13 | constructor(imgUrls, size) {
14 | if (size == null) { size = 900000; }
15 | const aCubeMap = THREE.ImageUtils.loadTextureCube(imgUrls);
16 | aCubeMap.format = THREE.RGBFormat;
17 | const aShader = THREE.ShaderLib['cube'];
18 | aShader.uniforms['tCube'].value = aCubeMap;
19 | const aSkyBoxMaterial = new (THREE.ShaderMaterial)({
20 | fragmentShader: aShader.fragmentShader,
21 | vertexShader: aShader.vertexShader,
22 | uniforms: aShader.uniforms,
23 | depthWrite: false,
24 | side: THREE.BackSide});
25 | super(new (THREE.BoxGeometry)(size, size, size), aSkyBoxMaterial)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/extras/ShaderLib.js:
--------------------------------------------------------------------------------
1 | THREE.ShaderLib['gradient'] = {
2 | vertexShader: [
3 | "varying vec3 vWorldPosition;",
4 |
5 | "void main() {",
6 | " vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
7 | " vWorldPosition = worldPosition.xyz;",
8 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
9 | "}"
10 | ].join("\n"),
11 | fragmentShader: [
12 | "uniform vec3 topColor;",
13 | "uniform vec3 bottomColor;",
14 | "uniform float offset;",
15 | "uniform float exponent;",
16 |
17 | "varying vec3 vWorldPosition;",
18 |
19 | "void main() {",
20 | " float h = normalize( vWorldPosition + offset ).y;",
21 | " gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 );",
22 | "}"
23 | ].join("\n")
24 | };
25 |
26 | THREE.ShaderLib['sample'] = {
27 | vertexShader: [
28 | ""
29 | ].join("\n"),
30 | fragmentShader: [
31 | ""
32 | ].join("\n")
33 | };
34 |
--------------------------------------------------------------------------------
/workspace/games/test/platformer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | platformer
10 |
14 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/workspace/games/test/main/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | main tests
10 |
14 |
15 |
16 |
17 |
18 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/workspace/games/controller2/LandingScene.js:
--------------------------------------------------------------------------------
1 | class LandingScene extends Scene {
2 | init(options) {
3 | let buttons = []
4 | this.buttons = buttons
5 |
6 | let camera = Hodler.get('camera')
7 | camera.position.set(0, 0, 10)
8 | camera.lookAt(new THREE.Vector3(0, 0, 0))
9 |
10 | this.add(new THREE.AmbientLight())
11 |
12 | let button1 = new Button3D('scan qr')
13 | button1.position.set(0, 1.5, 0)
14 | button1.onClick = () => {
15 | window.location.href = `zxing://scan/?ret=${window.location.href}?room={CODE}`
16 | }
17 | this.add(button1)
18 | buttons.push(button1)
19 |
20 | let button2 = new Button3D('join')
21 | button2.onClick = () => {
22 | console.log('switch to join scene')
23 | }
24 | button2.position.set(0, -1.5, 0)
25 | this.add(button2)
26 | buttons.push(button2)
27 | }
28 |
29 | tick(tpf) {
30 | this.buttons.forEach((button) => {
31 | button.tick(tpf)
32 | })
33 | }
34 |
35 | doMouseEvent(event, raycaster) {
36 | this.buttons.forEach((button) => {
37 | button.doMouseEvent(event, raycaster)
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/workspace/games/test/networking/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | networking
8 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | client
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/workspace/games/test/main/Scene2.js:
--------------------------------------------------------------------------------
1 | class Scene2 extends Scene {
2 | init(options) {
3 | let camera = resetCamPosition(20)
4 | camera.position.set(0, 0, 20)
5 | camera.lookAt(new THREE.Vector3(0, 0, 0))
6 |
7 | // Utils.toggleOrbitControls()
8 | this.add(new THREE.AmbientLight())
9 | this.add(new Sky())
10 |
11 | let geometry = new THREE.BoxGeometry( 1, 1, 1 )
12 | let material = new THREE.MeshBasicMaterial( { color: 0x4d4d4d } )
13 | let cube = new THREE.Mesh( geometry, material )
14 | this.add(cube)
15 | this.cube = cube
16 |
17 | let control = new PositionXZRotationYControls()
18 | this.control = control
19 | }
20 |
21 | uninit() {
22 | // Utils.toggleOrbitControls()
23 | }
24 |
25 | tick(tpf) {
26 | this.control.tick(tpf)
27 |
28 | this.cube.position.x += this.control.velocity.x
29 | this.cube.position.y -= this.control.velocity.z
30 | }
31 |
32 | doKeyboardEvent(event) {
33 | switchScene(event)
34 | this.control.doKeyboardEvent(event)
35 | }
36 |
37 | doGamepadEvent(event, gamepadIndex) {
38 | this.control.doGamepadEvent(event, gamepadIndex)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/workspace/games/test/main/Scene3.js:
--------------------------------------------------------------------------------
1 | class Scene3 extends Scene {
2 | init(options) {
3 | let camera = resetCamPosition(20)
4 | camera.position.set(0, 0, 20)
5 | camera.lookAt(new THREE.Vector3(0, 0, 0))
6 |
7 | // Utils.toggleOrbitControls()
8 | this.add(new THREE.AmbientLight())
9 | this.add(new Sky())
10 |
11 | let geometry = new THREE.BoxGeometry( 1, 1, 1 )
12 | let material = new THREE.MeshBasicMaterial( { color: 0x4d4d4d } )
13 | let cube = new THREE.Mesh( geometry, material )
14 | this.add(cube)
15 | this.cube = cube
16 |
17 | let control = new PositionXZRotationYControls()
18 | this.control = control
19 | }
20 |
21 | uninit() {
22 | // Utils.toggleOrbitControls()
23 | }
24 |
25 | tick(tpf) {
26 | this.control.tick(tpf)
27 |
28 | this.cube.position.x += this.control.velocity.x
29 | this.cube.position.y -= this.control.velocity.z
30 | }
31 |
32 | doKeyboardEvent(event) {
33 | switchScene(event)
34 | this.control.doKeyboardEvent(event)
35 | }
36 |
37 | doGamepadEvent(event, gamepadIndex) {
38 | this.control.doGamepadEvent(event, gamepadIndex)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/objects/Mirror.js:
--------------------------------------------------------------------------------
1 | class Mirror extends THREE.Reflector {
2 | constructor (options) {
3 | let renderer = Hodler.get('renderer');
4 | let camera = Hodler.get('camera');
5 | let size = new THREE.Vector2()
6 | renderer.getSize(size)
7 |
8 | if (options == null) { options = {}; }
9 | if (options.width == null) { options.width = Utils.PLANE_DEFAULT_WIDTH; }
10 | if (options.height == null) { options.height = Utils.PLANE_DEFAULT_HEIGHT; }
11 | if (options.mirror == null) { options.mirror = {}; }
12 | if (options.mirror.clipBias == null) { options.mirror.clipBias = Utils.MIRROR_DEFAULT_CLIP_BIAS; }
13 | if (options.mirror.textureWidth == null) { options.mirror.textureWidth = size.x * camera.aspect }
14 | if (options.mirror.textureHeight == null) { options.mirror.textureHeight = size.y * camera.aspect }
15 | if (options.mirror.color == null) { options.mirror.color = Utils.MIRROR_DEFAULT_COLOR; }
16 | if (options.mirror.recursion == null) { options.mirror.color = Utils.MIRROR_DEFAULT_RECURSION; }
17 |
18 | var geometry = new THREE.PlaneBufferGeometry(options.width, options.height);
19 | super(geometry, options.mirror)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/workspace/assets/particles/hit.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "particle",
3 | "textures": [
4 | {
5 | "libPath": "/workspace/assets/textures/spe_smokeparticle.png"
6 | }
7 | ],
8 | "particle": [
9 | "[",
10 | " {",
11 | " texture: {",
12 | " value: AssetManager.get('spe_smokeparticle.png')",
13 | " },",
14 | " maxParticleCount: 100,",
15 | " emitters: [",
16 | " {",
17 | " particleCount: 100,",
18 | " activeMultiplier: 40,",
19 | " maxAge: {",
20 | " value: 0.5",
21 | " },",
22 | " type: SPE.distributions.SPHERE,",
23 | " position: {",
24 | " radius: 0.5",
25 | " },",
26 | " velocity: {",
27 | " value: new THREE.Vector3(6),",
28 | " spread:new THREE.Vector3(3),",
29 | " },",
30 | " size: {",
31 | " value: 3",
32 | " },",
33 | " color: {",
34 | " value: [new THREE.Color('white'), new THREE.Color('red')]",
35 | " },",
36 | " opacity: {",
37 | " value: [0.1, 0]",
38 | " }",
39 | " }",
40 | " ]",
41 | " },",
42 | "]"
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/workspace/assets/particles/basic.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "particle",
3 | "textures": [
4 | {
5 | "libPath": "/workspace/assets/textures/spe_smokeparticle.png"
6 | }
7 | ],
8 | "particle": [
9 | "[",
10 | " {",
11 | " texture: {",
12 | " value: AssetManager.get('spe_smokeparticle.png')",
13 | " },",
14 | " emitters: [",
15 | " {",
16 | " particleCount: 2000,",
17 | " maxAge: {",
18 | " value: 2",
19 | " },",
20 | " position: {",
21 | " value: new THREE.Vector3(0, 0, 0),",
22 | " spread: new THREE.Vector3( 0, 0, 0 )",
23 | " },",
24 | " acceleration: {",
25 | " value: new THREE.Vector3(0, -10, 0),",
26 | " spread: new THREE.Vector3( 10, 0, 10 )",
27 | " },",
28 | " velocity: {",
29 | " value: new THREE.Vector3(0, 25, 0),",
30 | " spread: new THREE.Vector3(10, 7.5, 10)",
31 | " },",
32 | " size: {",
33 | " value: 1",
34 | " },",
35 | " color: {",
36 | " value: [new THREE.Color('white'), new THREE.Color('red')]",
37 | " },",
38 | " }",
39 | " ]",
40 | " },",
41 | "]"
42 | ]
43 | }
44 |
--------------------------------------------------------------------------------
/workspace/assets/particles/fire-small.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "particle",
3 | "textures": [
4 | {
5 | "libPath": "/workspace/assets/textures/spe_star.png"
6 | }
7 | ],
8 | "particle": [
9 | "[",
10 | " {",
11 | " texture: {",
12 | " value: AssetManager.get('spe_star.png')",
13 | " },",
14 | " depthTest: true,",
15 | " depthWrite: false,",
16 | " blending: THREE.AdditiveBlending,",
17 | " emitters: [",
18 | " {",
19 | " type: SPE.distributions.CUBE,",
20 | " particleCount: 500,",
21 | " maxAge: {",
22 | " value: 2,",
23 | " spread: 1",
24 | " },",
25 | " position: {",
26 | " value: new THREE.Vector3(0, 0, 0),",
27 | " spread: new THREE.Vector3(0.5, 0, 0.5)",
28 | " },",
29 | " acceleration: {",
30 | " value: new THREE.Vector3(0, 0.2, 0)",
31 | " },",
32 | " velocity: {",
33 | " value: new THREE.Vector3(0, 0.2, 0)",
34 | " },",
35 | " size: {",
36 | " value: [1, 2, 0.5, 0.2]",
37 | " },",
38 | " color: {",
39 | " value: [new THREE.Color('#DAA520'), new THREE.Color('#FFD700'), new THREE.Color('#DAA520')]",
40 | " },",
41 | " opacity: {",
42 | " value: [0.75, 0.5, 0]",
43 | " }",
44 | " }",
45 | " ]",
46 | " }",
47 | "]"
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/workspace/assets/particles/fireflies.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "particle",
3 | "textures": [
4 | {
5 | "libPath": "/workspace/assets/textures/spe_star.png"
6 | }
7 | ],
8 | "particle": [
9 | "[",
10 | " {",
11 | " texture: {",
12 | " value: AssetManager.get('spe_star.png'),",
13 | " },",
14 | " depthTest: true,",
15 | " depthWrite: false,",
16 | " blending: THREE.AdditiveBlending,",
17 | " emitters: [",
18 | " {",
19 | " type: SPE.distributions.SPHERE,",
20 | " particleCount: 200,",
21 | " maxAge: {",
22 | " value: 2,",
23 | " spread: 1",
24 | " },",
25 | " acceleration: {",
26 | " spread: new THREE.Vector3(1, 1, 1)",
27 | " },",
28 | " velocity: {",
29 | " spread: new THREE.Vector3(3, 3, 3)",
30 | " },",
31 | " position: {",
32 | " radius: 10,",
33 | " radiusScale: new THREE.Vector3(1, 1, 1),",
34 | " randomise: true",
35 | " },",
36 | " size: {",
37 | " value: [0.5, 2, 0.5],",
38 | " spread: [1, 1, 1]",
39 | " },",
40 | " color: {",
41 | " value: [new THREE.Color('#DAA520'), new THREE.Color('#FFD700'), new THREE.Color('#DAA520')]",
42 | " },",
43 | " opacity: {",
44 | " value: [0, 0.5, 0]",
45 | " }",
46 | " }",
47 | " ]",
48 | " }",
49 | "]"
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/tutorials/BLENDER.md:
--------------------------------------------------------------------------------
1 | ## Exporting from Blender
2 |
3 | To export to glTF, the recommended format by three.js, you need to install the
4 | [glTF-Blender-Exporter](https://github.com/KhronosGroup/glTF-Blender-Exporter)
5 | blender addon.
6 |
7 | * [Download the exporter](https://github.com/KhronosGroup/glTF-Blender-Exporter/archive/master.zip)
8 | * unzip `scripts/addons/io_scene_gltf2` to `~/.config/blender/VERSION/scripts/addons/`
9 | * enable the addon from Blender User Preferences
10 | * export to glb as it packs all the resources in 1 file
11 |
12 | ## Export many script
13 |
14 | ```
15 | blender ../path/to.blend --python export_all_glb.py
16 | ```
17 |
18 | ```
19 | import bpy
20 | import os
21 | from time import sleep
22 |
23 | def clear_selection():
24 | for obj in bpy.context.scene.objects:
25 | obj.select = False
26 |
27 | def export_all_fbx():
28 | filepath = bpy.data.filepath
29 | outputFolder = os.path.dirname(filepath)
30 |
31 | objects = bpy.data.objects
32 | for object in objects:
33 | clear_selection()
34 | object.select = True
35 | object.location = (0, 0, 0)
36 | exportPath = "%s/%s.glb" % (outputFolder, object.name)
37 | bpy.ops.export_scene.glb(filepath=exportPath,
38 | export_selected=True,
39 | export_apply=True)
40 |
41 | export_all_fbx()
42 | bpy.ops.wm.quit_blender()
43 | ```
44 |
--------------------------------------------------------------------------------
/workspace/assets/particles/bubbles.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "particle",
3 | "textures": [
4 | {
5 | "libPath": "/workspace/assets/textures/spe_bubble.png"
6 | }
7 | ],
8 | "particle": [
9 | "[",
10 | " {",
11 | " texture: {",
12 | " value: AssetManager.get('spe_bubble.png')",
13 | " },",
14 | " depthTest: true,",
15 | " depthWrite: false,",
16 | " blending: THREE.NormalBlending,",
17 | " emitters: [",
18 | " {",
19 | " type: SPE.distributions.CUBE,",
20 | " particleCount: 40,",
21 | " maxAge: {",
22 | " value: 2,",
23 | " spread: 1.5",
24 | " },",
25 | " position: {",
26 | " value: new THREE.Vector3(0, 0, 0),",
27 | " spread: new THREE.Vector3(10, 0, 1)",
28 | " },",
29 | " acceleration: {",
30 | " value: new THREE.Vector3(0, 0.5, 0),",
31 | " spread: new THREE.Vector3(0.1, 0.1, 0.1)",
32 | " },",
33 | " velocity: {",
34 | " value: new THREE.Vector3(0, 1, 0),",
35 | " spread: new THREE.Vector3(0.8, 0.8, 0.8)",
36 | " },",
37 | " size: {",
38 | " value: [2,5,5]",
39 | " },",
40 | " color: {",
41 | " value: [new THREE.Color('#67baca'), new THREE.Color('#FFFFFF')]",
42 | " },",
43 | " opacity: {",
44 | " value: [0.5, 0.9, 0.9, 0.9, 0.1]",
45 | " }",
46 | " }",
47 | " ]",
48 | " }",
49 | "]"
50 | ]
51 | }
52 |
--------------------------------------------------------------------------------
/src/extras/scenes/LoadingScene.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Loads assets on init and switches the scene to the specified callbackScene
3 | *
4 | * Example usage:
5 | *
6 | * let gameScene = new GameScene()
7 | * let loadingScene = new LoadingScene(gameScene, [
8 | * { type: "image", path: "assets/vrump.png },
9 | * ]
10 | *
11 | * Engine.start(loadingScene)
12 | */
13 | class LoadingScene extends Scene {
14 | constructor(callbackScene, assetsToLoad) {
15 | if (isBlank(callbackScene)) {
16 | throw 'callbackScene missing'
17 | }
18 | if (!isArray(assetsToLoad)) {
19 | throw 'assetsToLoad needs to be an array'
20 | }
21 | super()
22 | this.callbackScene = callbackScene
23 | this.assetsToLoad = assetsToLoad
24 | }
25 |
26 | init(options) {
27 | let camera = Hodler.get('camera')
28 | camera.position.set(0, 10, 15)
29 | camera.lookAt(new THREE.Vector3(0, 0, 0))
30 |
31 | this.initCallback(options)
32 |
33 | if (Config.instance.engine.debug) {
34 | console.info(`loadingScene started loading ${this.assetsToLoad.length} assets`)
35 | }
36 | Engine.switch(this.callbackScene, this.assetsToLoad)
37 | }
38 |
39 | initCallback(options) {
40 | let cube = Utils.box({ size: 1 })
41 | this.add(cube)
42 | this.cube = cube
43 | }
44 |
45 | tick(tpf) {
46 | if (!isBlank(this.cube)) {
47 | this.cube.rotation.x += tpf
48 | this.cube.rotation.y += tpf
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/tools/dependencies.dist.js:
--------------------------------------------------------------------------------
1 | // this file is included in the build process to offer the same behaviour
2 | // as dependencies.dev.js
3 | //
4 | // This allows switching from vrum.min.js to depedencies.dev.js easily
5 | let VRUM_DEPENDS = [
6 | ]
7 |
8 | const loadVrumScriptsWithDepends = (items, finishedCallback, relativeTo) => {
9 | if (relativeTo === undefined || relativeTo === null) { relativeTo = '' }
10 | if (items.length == 0) {
11 | if (finishedCallback instanceof Function) {
12 | finishedCallback()
13 | }
14 | return
15 | }
16 | const loadScript = (url, callback) => {
17 | var element = document.body;
18 | var script = document.createElement('script');
19 | script.type = 'text/javascript';
20 | script.src = url;
21 |
22 | script.onreadystatechange = callback;
23 | script.onload = callback;
24 |
25 | // Fire the loading
26 | element.appendChild(script);
27 | }
28 |
29 | items.reverse()
30 | let url = items.pop()
31 | if (url.startsWith("../") && relativeTo !== '') {
32 | url = `${relativeTo}/${url}`
33 | }
34 | url = new URL(url, window.location.href).href
35 | loadScript(url, () => {
36 | loadVrumScriptsWithDepends(items.reverse(), finishedCallback, relativeTo)
37 | })
38 | }
39 |
40 | const loadVrumScripts = (items, finishedCallback, relativeTo) => {
41 | let depends = VRUM_DEPENDS.concat(items)
42 | loadVrumScriptsWithDepends(depends, finishedCallback, relativeTo)
43 | }
44 |
--------------------------------------------------------------------------------
/workspace/games/test/networking/Networking.js:
--------------------------------------------------------------------------------
1 | let isMaster = true || MeshNetwork.isMaster()
2 | let room = Utils.guid()
3 |
4 | new QRCode("qrcode", { text: room, width: 128, height: 128 })
5 | document.querySelector('#qrcode-text').innerHTML = room
6 | document.querySelector('#client-link').href = `/workspace/games/controller/?room=${room}`
7 |
8 | let mn = new MeshNetwork()
9 | mn.setSignalingDebug(true)
10 | let socket = mn.connect('https://mesh.opinie-publica.ro', room, { audio: false, video: false })
11 |
12 | mn.onConnect = (peer) => {
13 | let element = document.createElement('div')
14 | element.setAttribute('id', `peer-${peer.cmKey}`)
15 |
16 | let elementKey = document.createElement('p')
17 | elementKey.innerHTML = peer.cmKey
18 | element.appendChild(elementKey)
19 |
20 | let elementAction = document.createElement('p')
21 | element.appendChild(elementAction)
22 |
23 | document.querySelector('#peers').appendChild(element)
24 | }
25 |
26 | mn.onData = (peer, data) => {
27 | element = document.querySelector(`#peer-${peer.cmKey}`)
28 | if (isBlank(element)) {
29 | console.error(`Could not find #peer-${peer.cmKey}`)
30 | return
31 | }
32 |
33 | element.children[1].innerHTML = JSON.stringify(data)
34 | }
35 |
36 | mn.onError = (peer, error) => {
37 | console.error(error)
38 | }
39 |
40 | mn.onClose = (peer) => {
41 | let row = document.querySelector(`#peer-${peer.cmKey}`)
42 | document.querySelector('#peers').removeChild(row)
43 | }
44 |
--------------------------------------------------------------------------------
/workspace/games/scene-editor/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | vrum.js scene-editor
10 |
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/extras/PolyfillRenderer.js:
--------------------------------------------------------------------------------
1 | // Displays a message if WebGL is not supported.
2 | //
3 | // To help customize the message there are 2 relevant ids:
4 | //
5 | // * vrum-webgl-warning-container
6 | // * vrum-webgl-warning-text
7 | //
8 | // For more detailed customizations, you can override
9 | //
10 | // * makeDomElement
11 | // * makeContainerElement
12 | //
13 | class PolyfillRenderer extends THREE.WebGLRenderer {
14 | constructor(parameters) {
15 | super(parameters)
16 | this.domElement = PolyfillRenderer.makeDomElement()
17 | }
18 |
19 | render(scene, camera) {}
20 |
21 | static makeContainerElement() {
22 | const element = document.createElement('div')
23 | element.setAttribute('id', 'vrum-webgl-warning-container')
24 | element.style.display = 'flex'
25 | element.style.position = 'absolute'
26 | element.style.width = '100%'
27 | element.style.height = '100%'
28 | element.style['align-items'] = 'center'
29 | element.style['text-align'] = 'center'
30 | element.style['background-color'] = 'black'
31 | element.style['color'] = 'white'
32 | element.style['z-index'] = Config.instance.ui.zIndex.noWebGL
33 | return element;
34 | }
35 |
36 | static makeDomElement() {
37 | let element = this.makeContainerElement()
38 |
39 | const text = document.createElement('div')
40 | text.setAttribute('id', 'vrum-webgl-warning-text')
41 | text.style.width = '100%'
42 | text.innerHTML = 'WebGL not supported'
43 | element.append(text)
44 |
45 | return element
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/workspace/games/test/threejs_benchmark.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | three.js benchmark
7 |
8 |
9 |
10 |
11 |
12 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/workspace/games/model-viewer/utils.js:
--------------------------------------------------------------------------------
1 | const stopPropagation = (event) => {
2 | let stopIt = (event) => { event.stopPropagation() }
3 | document.querySelectorAll('input[type=text]').forEach((e) => {
4 | e.addEventListener('keydown', stopIt)
5 | })
6 | }
7 |
8 | const loadModel = (url) => {
9 | let inputUrl = document.querySelector('#inputUrl')
10 | let scale = parseFloat(document.querySelector('#scale').value)
11 | if (!isBlank(url)) {
12 | inputUrl.value = url
13 | }
14 | Hodler.get('mainScene').loadModel(inputUrl.value, scale)
15 | const lastModels = Persist.getJson('lastModels')
16 | if (!lastModels.includes(inputUrl.value)) {
17 | lastModels.insert(0, inputUrl.value)
18 | while (lastModels.size() > 8) {
19 | lastModels.pop()
20 | }
21 | Persist.setJson('lastModels', lastModels)
22 | updateLastModels()
23 | }
24 | }
25 |
26 | const updateLastModels = () => {
27 | const lastModels = Persist.getJson('lastModels')
28 | const element = document.querySelector('#lastModels')
29 | element.innerHTML = ''
30 |
31 | lastModels.forEach((e) => {
32 | const button = document.createElement('span')
33 | button.className = 'button'
34 | button.setAttribute('onclick', `loadModel('${e}')`)
35 | button.innerHTML = AssetManager.getAssetKey({ path: e })
36 | element.append(button)
37 | })
38 | }
39 |
40 | let wireframe = false
41 | const toggleWireframe = () => {
42 | wireframe = !wireframe
43 | Utils.setWireframe(wireframe)
44 | }
45 |
46 | const toggleGird = () => {
47 | let grid = Hodler.get('scene').grid
48 | grid.visible = !grid.visible
49 | }
50 |
51 | const toggleSky = () => {
52 | let sky = Hodler.get('scene').sky
53 | sky.visible = !sky.visible
54 | }
55 |
--------------------------------------------------------------------------------
/src/extras/Playlist.js:
--------------------------------------------------------------------------------
1 | // Used for continously looping sounds from the SoundManager
2 | class Playlist {
3 | // @param [Array] keys
4 | constructor(keys) {
5 | if (!(keys instanceof Array)) { throw new Error('keys needs to be an array') }
6 | for (let key of Array.from(keys)) {
7 | if (!SoundManager.has(key)) {
8 | throw new Error(`key '${key}' not loaded in SoundManager`)
9 | }
10 | }
11 | this.items = new CyclicArray(keys)
12 | }
13 |
14 | // start playing the playlist
15 | //
16 | // @example
17 | // playlist = new Playlist(['shotgun', 'hit'])
18 | // playlist.play()
19 | //
20 | // @see getPlayingKey
21 | cmd(options){
22 | let audio
23 | options.key = this.items.get()
24 | if (options.type === 'volumeAll') {
25 | options.type = 'volume'
26 | for (let item of Array.from(this.items.items)) {
27 | options.key = item
28 | SoundManager.cmd(options)
29 | }
30 | } else {
31 | audio = SoundManager.cmd(options)
32 | }
33 | if (['play', 'fadeIn'].includes(options.type)) {
34 | audio._onend = []
35 | return audio.on('end', data => {
36 | this.items.next()
37 | return this.cmd(options)
38 | })
39 | } else if (['volume', 'volumeAll'].includes(options.type)) {
40 | // do nothing
41 | } else {
42 | return audio._onend = []
43 | }
44 | }
45 |
46 | // Get the key of the sound currently playing
47 | //
48 | // @example
49 | // playlist = new Playlist(['shotgun', 'hit'])
50 | // playlist.play()
51 | // SoundManager.pause(playlist.getPlayingKey())
52 | getPlayingKey() {
53 | return this.items.get()
54 | }
55 |
56 | // Get the audio object which is currently playing
57 | getPlayingAudio() {
58 | return SoundManager.get().items[this.getPlayingKey()]
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/vendor/rStats.css:
--------------------------------------------------------------------------------
1 | .alarm{
2 | color: #b70000;
3 | text-shadow: 0 0 0 #b70000,
4 | 0 0 1px #fff,
5 | 0 0 1px #fff,
6 | 0 0 2px #fff,
7 | 0 0 2px #fff,
8 | 0 0 3px #fff,
9 | 0 0 3px #fff,
10 | 0 0 4px #fff,
11 | 0 0 4px #fff;
12 | }
13 |
14 | .rs-base{
15 | position: absolute;
16 | z-index: 10000;
17 | padding: 10px;
18 | background-color: #222;
19 | font-size: 10px;
20 | line-height: 1.2em;
21 | width: 350px;
22 | font-family: 'Roboto Condensed', tahoma, sans-serif;
23 | left: 0;
24 | top: 0;
25 | overflow: hidden;
26 | }
27 |
28 | .rs-base h1{
29 | margin: 0;
30 | padding: 0;
31 | font-size: 1.4em;
32 | color: #fff;
33 | margin-bottom: 5px;
34 | cursor: pointer;
35 | }
36 |
37 | .rs-base div.rs-group{
38 | margin-bottom: 10px;
39 | }
40 |
41 | .rs-base div.rs-group.hidden{
42 | display: none;
43 | }
44 |
45 | .rs-base div.rs-fraction{
46 | position: relative;
47 | margin-bottom: 5px;
48 | }
49 |
50 | .rs-base div.rs-fraction p{
51 | width: 120px;
52 | text-align: right;
53 | margin: 0;
54 | padding: 0;
55 | }
56 |
57 | .rs-base div.rs-legend{
58 | position: absolute;
59 | line-height: 1em;
60 | }
61 |
62 | .rs-base div.rs-counter-base{
63 | color: gray;
64 | position: relative;
65 | margin: 2px 0;
66 | height: 1em;
67 | }
68 |
69 | .rs-base span.rs-counter-id{
70 | position: absolute;
71 | left: 0;
72 | top: 0;
73 | }
74 |
75 | .rs-base div.rs-counter-value{
76 | position: absolute;
77 | left: 90px;
78 | width: 30px;
79 | height: 1em;
80 | top: 0;
81 | text-align: right;
82 | }
83 |
84 | .rs-base canvas.rs-canvas{
85 | position: absolute;
86 | right: 0;
87 | }
88 |
--------------------------------------------------------------------------------
/workspace/assets/graffiti/majestic-frog-cover.json:
--------------------------------------------------------------------------------
1 | {
2 | "clearColor": "#ffffff",
3 | "width": 640,
4 | "height": 309,
5 | "plane": {
6 | "width": 6.4,
7 | "height": 3.09,
8 | "wSegments": 1,
9 | "hSegments": 1,
10 | "color": "#ff0000",
11 | "class": "PlaneBufferGeometry"
12 | },
13 | "kind": "graffiti",
14 | "items": [
15 | {
16 | "type": "image",
17 | "text": "Overlay text",
18 | "x": 0,
19 | "y": 0,
20 | "fillStyle": "#000000",
21 | "fillLineWidth": 1,
22 | "strokeLineWidth": 7,
23 | "font": "40px Helvetica",
24 | "asset": {
25 | "key": "vrum.png",
26 | "libPath": "/workspace/assets/textures/vrum.png"
27 | },
28 | "key": "vrum",
29 | "angle": 0
30 | },
31 | {
32 | "type": "image",
33 | "text": "or images",
34 | "x": 0,
35 | "y": 0,
36 | "fillStyle": "#000000",
37 | "font": "20px Helvetica",
38 | "fillLineWidth": 1,
39 | "strokeLineWidth": 7,
40 | "asset": {
41 | "key": "black-faded-border.png",
42 | "libPath": "/workspace/assets/textures/black-faded-border.png"
43 | },
44 | "key": "black-faded-border",
45 | "angle": 0
46 | },
47 | {
48 | "type": "text",
49 | "text": "The Majestic Frog",
50 | "fillStyle": "white",
51 | "fillLineWidth": 1,
52 | "strokeLineWidth": 7,
53 | "strokeStyle": "#fe3d3d",
54 | "font": "40px Helvetica",
55 | "x": 9,
56 | "y": 295
57 | },
58 | {
59 | "type": "bezier",
60 | "text": "Original Swing Album",
61 | "fillStyle": "white",
62 | "fillLineWidth": 2,
63 | "strokeLineWidth": 7,
64 | "font": "30px Helvetica",
65 | "x": 112,
66 | "y": -117,
67 | "curve": "20,157.2,130.02,100.0,150.5,246.2,492,176.3",
68 | "letterPadding": 7
69 | }
70 | ]
71 | }
72 |
--------------------------------------------------------------------------------
/workspace/assets/shaders/dissolve_shader.json:
--------------------------------------------------------------------------------
1 | {
2 | "kind": "shader",
3 | "tick": ["(tpf) => { if (this.uniforms.dissolve.value > 1) { this.uniforms.dissolve.value = 0 } this.uniforms.dissolve.value += tpf }"],
4 | "uniforms": "{ texture: { type: 't', value: AssetManager.get('spe_smokeparticle.png') }, noise: { type: 't', value: AssetManager.get('spe_smokeparticle.png') }, dissolve: { type: 'f', value: 0.0 } }",
5 | "fragment": "varying vec2 vUv;\nuniform sampler2D texture;\nuniform sampler2D noise;\n\nuniform float dissolve;\nvoid main() {\n vec4 color = texture2D( texture, vUv );\n float n = texture2D( noise, vUv ).x;\n n = ( n - dissolve ) * 50.0;\n if (n < 0.0) {\n discard;\n }\n if (n < 1.0) {\n color.r = 1.0; color.g = 0.5; color.b = 0.0;\n }\n gl_FragColor = color;\n}",
6 | "vertex": "varying vec2 vUv;\nuniform float morphTargetInfluences[ 8 ];\n\nvoid main() {\n vUv = uv;\n\n vec3 morphed = vec3( 0.0 );\n morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\n morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\n morphed += position;\n vec4 mvPosition;\n mvPosition = modelViewMatrix * vec4( morphed, 1.0 );\n gl_Position = projectionMatrix * mvPosition;\n //vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );\n}",
7 | "textures": [
8 | {
9 | "libPath": "/workspace/assets/textures/spe_smokeparticle.png",
10 | "destPath": "assets/spe_smokeparticle.png",
11 | "type": "texture"
12 | }
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/workspace/games/controller2/ControllerScene.js:
--------------------------------------------------------------------------------
1 | class ControllerScene extends Scene {
2 | init(options) {
3 | this.add(new THREE.AmbientLight(0xffffff))
4 | this.isPressed = false
5 | this.connect()
6 | }
7 |
8 | uninit() {
9 | if (!VirtualController.isAvailable()) { return }
10 | if (isBlank(this.vc)) { return }
11 | this.vc.uninit()
12 | }
13 |
14 | connect() {
15 | let mn = MeshNetwork.instance
16 | if (mn.isConnected()) { return }
17 |
18 | mn.connect('https://mesh.opinie-publica.ro', roomId, {
19 | cCallback: function () {
20 | Hodler.get('scene').addControls()
21 | },
22 | dcCallback: function () {
23 | // lost connection with socket.io
24 | }
25 | })
26 |
27 | mn.onData = (peer, data) => {}
28 | }
29 |
30 | getDirection(joystick) {
31 | let dS = (joystick.right() ? 'right' : '') + (joystick.up() ? 'up' : '') + (joystick.down() ? 'down' : '') + (joystick.left() ? 'left' : '')
32 | return dS || undefined
33 | }
34 |
35 | formatJoystick(joystick) {
36 | return {
37 | dX: joystick.deltaX(),
38 | dY: joystick.deltaY(),
39 | direction: this.getDirection(joystick),
40 | isPressed: joystick.isPressed
41 | }
42 | }
43 |
44 | addControls() {
45 | this.vc = new VirtualController({
46 | joystickLeft: {
47 | stickRadius: 60
48 | },
49 | joystickRight: {
50 | stickRadius: 60
51 | }
52 | })
53 | this.vc.trackIsPressed()
54 |
55 | this.setInterval(function() {
56 | let scene = Hodler.get('scene')
57 |
58 | let obj = {
59 | vrumKey: vrumKey,
60 | type: 'vrum-controller',
61 | joystickLeft: scene.formatJoystick(scene.vc.joystickLeft),
62 | joystickRight: scene.formatJoystick(scene.vc.joystickRight)
63 | }
64 |
65 | MeshNetwork.instance.emit(obj)
66 | }, 1/30 * 1000);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/extras/VideoRecorderManager.js:
--------------------------------------------------------------------------------
1 | /*
2 | * decaffeinate suggestions:
3 | * DS102: Remove unnecessary code created because of implicit returns
4 | * DS206: Consider reworking classes to avoid initClass
5 | * DS207: Consider shorter variations of null checks
6 | * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
7 | */
8 | // @nodoc
9 | var VideoRecorderManager = (function() {
10 | let instance = undefined;
11 | VideoRecorderManager = class VideoRecorderManager {
12 | static initClass() {
13 |
14 | instance = null;
15 |
16 | Singleton.VideoRecorderManager = class VideoRecorderManager {
17 |
18 | constructor() {
19 | this.recording = false;
20 | }
21 |
22 | capture(domElement) {
23 | if (this.recording === false) { return; }
24 | this.recorder.capture(domElement);
25 | }
26 |
27 | start() {
28 | if (this.recorder == null) {
29 | this.recorder = new CCapture(Config.instance.recorder);
30 | }
31 | this.recorder.start();
32 | this.recording = true;
33 | }
34 |
35 | stop() {
36 | this.recorder.stop();
37 | this.recording = false;
38 | this.recorder.save()
39 | }
40 |
41 | isRecording() {
42 | return this.recording
43 | }
44 | };
45 | }
46 |
47 | static get() {
48 | return instance != null ? instance : (instance = new Singleton.VideoRecorderManager());
49 | }
50 |
51 | static start() {
52 | this.get().start();
53 | }
54 |
55 | static stop() {
56 | this.get().stop();
57 | }
58 |
59 | static isRecording() {
60 | return this.get().isRecording()
61 | }
62 |
63 | static capture(domElement) {
64 | this.get().capture(domElement);
65 | }
66 | };
67 | VideoRecorderManager.initClass();
68 | return VideoRecorderManager;
69 | })();
70 |
--------------------------------------------------------------------------------
/src/extras/AfterEffects.js:
--------------------------------------------------------------------------------
1 | // Used to generate after effects and enable/disable on a scene/camera basis
2 | //
3 | // Example usage:
4 | //
5 | // Hodler.get('afterEffects').enable()
6 | //
7 | class AfterEffects {
8 | constructor() {
9 | this.enabled = false
10 | this.renderModel = new (THREE.RenderPass)(undefined, undefined) // scene, camera
11 | }
12 |
13 | render(tpf) {
14 | Hodler.get('renderer').clear()
15 | this.composer.render(tpf)
16 | }
17 |
18 | enable() {
19 | this.updateCamAndScene()
20 | this.composer = new THREE.EffectComposer(Hodler.get('renderer'))
21 | this.effects()
22 | this.enabled = true
23 | }
24 |
25 | disable() {
26 | this.enabled = false
27 | }
28 |
29 | toggle() {
30 | this.enabled ? this.disable() : this.enable()
31 | }
32 |
33 | updateCamAndScene() {
34 | this.renderModel.camera = Hodler.get('camera')
35 | this.renderModel.scene = Hodler.get('scene')
36 | }
37 |
38 | // Override this method with the desired effect. See AfterEffects.bloomFilm for
39 | // more details.
40 | effects() {
41 | }
42 |
43 | // These are methods which pre-define different effects
44 | //
45 | // Example usage:
46 | //
47 | // AfterEffects.prototype.effects = AfterEffects.bloomFilm
48 |
49 | static bloomFilm() {
50 | const effectBloom = new THREE.BloomPass(1, 5, 1.0, 2048)
51 | const effectFilm = new THREE.FilmPass(0.15, 0.95, 2048, false)
52 | effectFilm.renderToScreen = true
53 |
54 | this.composer.addPass(this.renderModel)
55 | this.composer.addPass(effectBloom)
56 | this.composer.addPass(effectFilm)
57 | }
58 |
59 | static bloomCopy() {
60 | const effectBloom = new (THREE.BloomPass)(1.25)
61 | const effectCopy = new (THREE.ShaderPass)(THREE.CopyShader)
62 | effectCopy.renderToScreen = true
63 |
64 | this.composer.addPass(this.renderModel)
65 | this.composer.addPass(effectBloom)
66 | this.composer.addPass(effectCopy)
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/tools/newGame.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // Creates a new game using workspace/games/project as a template
4 | //
5 | // 1. copies the template to the destination folder
6 | // 2. copies vrum.js
7 |
8 | const colors = require('colors')
9 | const ncp = require('ncp').ncp
10 | const fs = require('fs')
11 | const common = require('./common')
12 | const path = require('path')
13 | const readline = require('./common').readline
14 |
15 | const argv = process.argv.slice(2)
16 |
17 | console.log('Welcome to vrum.js new game creator!')
18 |
19 | let vrumMinJsPath = path.join(common.distFolder, 'vrum.min.js')
20 |
21 | if (!fs.existsSync(vrumMinJsPath)) {
22 | console.error(`vrum.min.js is missing. Run 'yarn build' first`.red)
23 | process.exit(1)
24 | }
25 |
26 | const newGame = (name, callback) => {
27 | var targetDir = 'workspace/games/'
28 | var fullPath = `${targetDir}${name}`
29 |
30 | if (name == '' || name == undefined || name == null || fullPath === targetDir) {
31 | console.error('Name missing'.red)
32 | process.exit(1)
33 | }
34 |
35 | if (name.search(/^[a-zA-Z0-9-_]+$/) == -1) {
36 | console.error('Invalid name. Only alpha, numeric, - and _ characters allowed')
37 | process.exit(1)
38 | }
39 |
40 | if (fs.existsSync(fullPath)) {
41 | console.error(`Game '${name}' already exists`.red)
42 | process.exit(1)
43 | }
44 |
45 | ncp('workspace/games/project', fullPath, function (err) {
46 | if (err) {
47 | console.error('Could not copy workspace/games/project'.red)
48 | process.exit(1)
49 | }
50 | common.cp(vrumMinJsPath, `${fullPath}/vrum.min.js`)
51 | console.log(`Game '${name}' sucessfully created in '${fullPath}'`.green)
52 |
53 | callback()
54 | })
55 | }
56 |
57 | if (argv.length == 0) {
58 | const rl = readline()
59 | rl.question('Game name: '.yellow, (name) => {
60 | newGame(name, () => {
61 | rl.close()
62 | })
63 | })
64 | } else {
65 | newGame(argv[0], () => {})
66 | }
67 |
--------------------------------------------------------------------------------
/src/extras/RStatsManager.js:
--------------------------------------------------------------------------------
1 | class RStatsManager {
2 | constructor() {
3 | this.glS = new glStats(); // init at any point
4 | this.tS = new threeStats( Hodler.get('renderer') ); // init after WebGLRenderer is created
5 | this.rS = new rStats( {
6 | CSSPath: '/src/vendor/',
7 | values: {
8 | frame: { caption: 'Total frame time (ms)', over: 16 },
9 | fps: { caption: 'Framerate (FPS)', below: 30 },
10 | calls: { caption: 'Calls (three.js)', over: 3000 },
11 | raf: { caption: 'Time since last rAF (ms)' },
12 | rstats: { caption: 'rStats update (ms)' }
13 | },
14 | groups: [
15 | { caption: 'Framerate', values: [ 'fps', 'raf' ] },
16 | { caption: 'Frame Budget', values: [ 'frame', 'texture', 'setup', 'render' ] }
17 | ],
18 | fractions: [
19 | { base: 'frame', steps: [ 'action1', 'render' ] }
20 | ],
21 | plugins: [
22 | this.tS,
23 | this.glS
24 | ]
25 | } );
26 | }
27 |
28 | static startMeasure() {
29 | if (isBlank(RStatsManager.instance)) { return }
30 | let inst = RStatsManager.instance
31 |
32 | inst.rS( 'frame' ).start();
33 | inst.glS.start();
34 |
35 | inst.rS( 'frame' ).start();
36 | inst.rS( 'rAF' ).tick();
37 | inst.rS( 'FPS' ).frame();
38 |
39 | inst.rS( 'action1' ).start();
40 | }
41 |
42 | static midMeasure() {
43 | if (isBlank(RStatsManager.instance)) { return }
44 | let inst = RStatsManager.instance
45 |
46 | inst.rS( 'action1' ).end();
47 | inst.rS( 'render' ).start();
48 | }
49 |
50 | static endMeasure() {
51 | if (isBlank(RStatsManager.instance)) { return }
52 | let inst = RStatsManager.instance
53 | inst.rS( 'render' ).end();
54 |
55 | inst.rS( 'frame' ).end();
56 | inst.rS().update();
57 | }
58 |
59 | static toggleStats() {
60 | RStatsManager.instance = new RStatsManager()
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tutorials/DISTRIBUTE.md:
--------------------------------------------------------------------------------
1 | # Distribute
2 |
3 | Please follow [the previous tutorial](/tutorials/INSTALL.md) if you want to know how
4 | to setup the game template for development.
5 |
6 | ## About
7 |
8 | Now that we have our game, we want other to play it, or at least test it.
9 |
10 | There are several ways to distribute your app:
11 |
12 | * serve it from a webserver
13 | * build it as an executable
14 | * deploy it to github pages
15 |
16 | ## Webserver
17 |
18 | Serve it from a webserver. Won't go over this step in too much detail, but in
19 | the end, we have some html, js and css files. If we setup paths correctly, we
20 | can just serve all the files from a webserver. Doesn't really matter which one.
21 |
22 | ## Executable
23 |
24 | To build an executable, you need the vrum repo. Go to the root of the repo and
25 | run:
26 |
27 | ```
28 | yarn dist:exe
29 | ```
30 |
31 | Input the path to the source code. A bunch of text and warnings will fly on screen,
32 | but the end result should be a folder called `dist` which contains different
33 | executables for different platforms: linux, mac, windows
34 |
35 | ## GithubPages
36 |
37 | To deploy to Github Pages, you need the vrum repo and the game as a git repo.
38 | Run:
39 |
40 | ```
41 | yarn dist:web
42 | ```
43 |
44 | Input the path to the source code. The script will check for a git repo and
45 | deploy it to a branch called `gh-pages` which will activate auto building by Github.
46 |
47 | Open the URL of the repo to see your game in action. If you don't know the URL, you
48 | can find it in the github pages section of your repo settings page.
49 |
50 | Example: [https://github.com/mess110/vrum/settings](https://github.com/mess110/vrum/settings)
51 |
52 | gg
53 |
54 | ## Android
55 |
56 | TODO: but basically use a WebView
57 |
58 | ## LiveReload
59 |
60 | When running in development mode, we also add [live.js](http://livejs.com/) to
61 | the list of dependencies so you don't have to reload the page when you save
62 | your files.
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vrum",
3 | "version": "0.1.0",
4 | "author": "Cristian Mircea Messel ",
5 | "license": "MIT",
6 | "scripts": {
7 | "postinstall": "yarn build",
8 | "http": "http-server -c-1 -o",
9 | "https": "http-server -c-1 -S -C cert.pem -o",
10 | "genkey": "openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem",
11 | "build": "node src/tools/build.js",
12 | "dist:exe": "yarn build && yarn clean:tmp && node src/tools/dist.js && cd tmp && yarn install && cd .. && yarn clean:tmp",
13 | "dist:web": "yarn build && node src/tools/publish.js",
14 | "clean:tmp": "rm -rf ./tmp",
15 | "new_game": "node src/tools/newGame.js",
16 | "start": "node src/tools/help.js",
17 | "h": "yarn start"
18 | },
19 | "dependencies": {
20 | "@tweenjs/tween.js": "^17.2.0",
21 | "camera-controls": "yomotsu/camera-controls",
22 | "ccapture.js": "^1.1.0",
23 | "file-saver": "^1.3.8",
24 | "fontfaceobserver": "^2.1.0",
25 | "howler": "1.1.29",
26 | "html2canvas": "^1.0.0-alpha.12",
27 | "ocean": "jbouny/ocean",
28 | "qrcodejs": "davidshimjs/qrcodejs",
29 | "shader-particle-engine": "squarefeet/ShaderParticleEngine",
30 | "stats.js": "mrdoob/stats.js",
31 | "rstats": "spite/rstats",
32 | "three": "^0.116.0",
33 | "threex.dynamictexture": "jeromeetienne/threex.dynamictexture",
34 | "threex.keyboardstate": "jeromeetienne/threex.keyboardstate",
35 | "threex.volumetricspotlight": "jeromeetienne/threex.volumetricspotlight",
36 | "threex.windowresize": "jeromeetienne/threex.windowresize",
37 | "virtualjoystick.js": "jeromeetienne/virtualjoystick.js"
38 | },
39 | "devDependencies": {
40 | "opn": "^6.0.0",
41 | "brace": "^0.11.1",
42 | "colors": "^1.3.2",
43 | "concat-files": "^0.1.1",
44 | "gh-pages": "^2.0.1",
45 | "glob": "^7.1.3",
46 | "http-server": "^0.11.1",
47 | "ncp": "^2.0.0",
48 | "uglify-es": "^3.3.9"
49 | },
50 | "engines": {
51 | "node": ">=10.13"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/tools/common.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const readline = require('readline');
4 | const fs = require('fs')
5 |
6 | const rl = () => {
7 | return readline.createInterface({
8 | input: process.stdin,
9 | output: process.stdout
10 | });
11 | }
12 |
13 | const injectHTML = (htmlPath, injectString) => {
14 | // TODO check for index.html
15 | let lines = fs.readFileSync(htmlPath, 'utf-8').split('\n')
16 | let lineIndex = 0
17 | let foundIndex = undefined
18 | lines.forEach((line) => {
19 | if (line.indexOf('