├── .gitignore
├── .DS_Store
├── assets
├── oh.mp3
├── clap.mp3
├── sprite.png
├── title.png
├── readme
│ ├── game.png
│ ├── video.jpg
│ └── interface.png
└── sprite org.png
├── public
├── assets
│ ├── clap.mp3
│ ├── oh.mp3
│ ├── sprite.png
│ ├── title.png
│ ├── readme
│ │ ├── game.png
│ │ ├── video.jpg
│ │ └── interface.png
│ └── sprite org.png
├── css
│ ├── style.css.map
│ └── style.css
├── index.html
└── datasets
│ ├── knips-weee.json
│ ├── default_40-40.json
│ └── default.json
├── js
├── game
│ ├── Moon.js
│ ├── Backdrop.js
│ ├── Number.js
│ ├── BigNumber.js
│ ├── Mountain.js
│ ├── Title.js
│ ├── Section.js
│ ├── ScoreBoard.js
│ ├── Icon.js
│ ├── Player.js
│ ├── Obstacle.js
│ └── Game.js
├── main.js
└── ai
│ ├── KNN.js
│ ├── Microphone.js
│ └── AudioClassifier.js
├── package.json
├── html
└── index.html
├── style
└── main.styl
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/.DS_Store
--------------------------------------------------------------------------------
/assets/oh.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/oh.mp3
--------------------------------------------------------------------------------
/assets/clap.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/clap.mp3
--------------------------------------------------------------------------------
/assets/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/sprite.png
--------------------------------------------------------------------------------
/assets/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/title.png
--------------------------------------------------------------------------------
/assets/readme/game.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/readme/game.png
--------------------------------------------------------------------------------
/assets/sprite org.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/sprite org.png
--------------------------------------------------------------------------------
/public/assets/clap.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/clap.mp3
--------------------------------------------------------------------------------
/public/assets/oh.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/oh.mp3
--------------------------------------------------------------------------------
/assets/readme/video.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/readme/video.jpg
--------------------------------------------------------------------------------
/public/assets/sprite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/sprite.png
--------------------------------------------------------------------------------
/public/assets/title.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/title.png
--------------------------------------------------------------------------------
/assets/readme/interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/assets/readme/interface.png
--------------------------------------------------------------------------------
/public/assets/readme/game.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/readme/game.png
--------------------------------------------------------------------------------
/public/assets/sprite org.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/sprite org.png
--------------------------------------------------------------------------------
/public/assets/readme/video.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/readme/video.jpg
--------------------------------------------------------------------------------
/public/assets/readme/interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lassse/sound-controlled-intergalactic-teddy/HEAD/public/assets/readme/interface.png
--------------------------------------------------------------------------------
/js/game/Moon.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main.js'
3 |
4 | class Moon {
5 | constructor() {
6 | this.image = Q.spriteImage
7 | this.x = 10
8 | this.y = 10
9 | this.width = 90
10 | this.height = 90
11 |
12 | this.sourceX = 100
13 | this.sourceY = 200
14 | this.sourceWidth = 90
15 | this.sourceHeight = 90
16 |
17 | }
18 |
19 | render(context) {
20 |
21 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
22 | }
23 | }
24 |
25 | export default Moon
--------------------------------------------------------------------------------
/js/game/Backdrop.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main.js'
3 |
4 | class Backdrop {
5 | constructor(x) {
6 | this.image = Q.spriteImage
7 | this.x = x
8 | this.y = 0
9 | this.width = 1400
10 | this.height = 572
11 |
12 | this.sourceX = 428
13 | this.sourceY = 196
14 | this.sourceWidth = 1400
15 | this.sourceHeight = 572
16 | }
17 |
18 | render(context) {
19 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
20 | }
21 | }
22 |
23 | export default Backdrop
--------------------------------------------------------------------------------
/js/game/Number.js:
--------------------------------------------------------------------------------
1 | import Q from './../main.js'
2 |
3 | class Number {
4 | constructor() {
5 | this.image = Q.spriteImage
6 | this.value = null
7 |
8 | this.width = 20
9 | this.height = 28
10 |
11 | this.x = 0
12 | this.y = 0
13 |
14 | this.sourceX = 116
15 | this.sourceY = 1500
16 | this.sourceWidth = 20
17 | this.sourceHeight = 28
18 | }
19 |
20 | set(value) {
21 | this.value = value
22 | }
23 |
24 | clear() {
25 | this.value = 0
26 | }
27 |
28 | render(context) {
29 | context.drawImage(this.image, this.sourceX + (this.sourceWidth * (this.value)), this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
30 | }
31 | }
32 |
33 | export default Number
--------------------------------------------------------------------------------
/js/game/BigNumber.js:
--------------------------------------------------------------------------------
1 | import Q from './../main.js'
2 |
3 | class BigNumber {
4 | constructor() {
5 | this.image = Q.spriteImage
6 | this.value = null
7 |
8 | this.width = 80
9 | this.height = 116
10 |
11 | this.x = 0
12 | this.y = 0
13 |
14 | this.sourceX = 630
15 | this.sourceY = 1980
16 | this.sourceWidth = 80
17 | this.sourceHeight = 116
18 | this.show = true
19 | }
20 |
21 | set(value) {
22 | this.show = true
23 | this.value = value
24 | }
25 |
26 | clear() {
27 | this.value = 0
28 | this.show = false
29 | }
30 |
31 | render(context) {
32 | if (this.show) {
33 | context.drawImage(this.image, this.sourceX + (this.sourceWidth * (this.value)), this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
34 | }
35 | }
36 | }
37 |
38 | export default BigNumber
--------------------------------------------------------------------------------
/js/game/Mountain.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main.js'
3 |
4 | class Mountain {
5 | constructor(index) {
6 | this.image = Q.spriteImage
7 |
8 | if (index === 0) {
9 | this.x = 0
10 | this.y = 60
11 | this.width = 1400
12 | this.height = 453
13 | this.sourceX = 428
14 | this.sourceY = 768
15 | this.sourceWidth = 1400
16 | this.sourceHeight = 453
17 | }else if (index === 1) {
18 | this.x = 0
19 | this.y = 200
20 | this.width = 1400
21 | this.height = 342
22 | this.sourceX = 428
23 | this.sourceY = 1220
24 | this.sourceWidth = 1400
25 | this.sourceHeight = 342
26 | }else if (index === 2) {
27 | this.x = 0
28 | this.y = 368
29 | this.width = 1400
30 | this.height = 100
31 | this.sourceX = 428
32 | this.sourceY = 1560
33 | this.sourceWidth = 1400
34 | this.sourceHeight = 100
35 | }
36 |
37 | }
38 |
39 | render(context) {
40 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
41 | }
42 | }
43 |
44 | export default Mountain
--------------------------------------------------------------------------------
/public/css/style.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../../style/main.styl"],"names":[],"mappings":"AAAA;AAAM;EACL,QAAQ,EAAR;EACA,OAAO,KAAP;EACA,QAAQ,KAAR;EACA,SAAS,KAAT;EACA,iBAAiB,OAAjB;EACA,aAAa,OAAb;EACA,YAAY,KAAZ;;AAID;EACC,UAAS,SAAT;EACA,YAAW,KAAX;EACA,OAAO,MAAP;EACA,QAAQ,MAAR;EAEA,SAAQ,KAAR;EACA,iBAAiB,OAAjB;EACA,aAAa,OAAb;EACA,gBAAgB,OAAhB;EACA,KAAK,KAAL;EACA,OAAO,KAAP;EACA,aAA0B,yBAA1B;EACA,WAAW,KAAX;;AAGD;EACC,UAAU,SAAV;EACA,OAAO,MAAP;EACA,QAAQ,MAAR;EACA,MAAM,KAAN;EACA,WAAsB,0BAAtB;;AAOD;EACC,SAAS,KAAT;EACA,UAAS,SAAT;EACA,KAAK,IAAL;EACA,MAAM,IAAN;EACA,YAAY,WAAZ;EACA,OAAO,MAAP;EACA,YAAW,MAAX;EACA,SAAS,KAAT;EACA,SAAS,IAAT;EACA,YAAY,KAAZ;EACA,OAAO,KAAP;EACA,aAA0B,yBAA1B;EACA,WAAW,KAAX;EACA,aAAa,IAAb;;AAGA;EACC,UAAS,SAAT;EACA,KAAK,KAAL;EACA,OAAO,KAAP;EACA,SAAS,KAAT;EACA,WAAW,KAAX;EACA,aAAY,KAAZ;EACA,QAAQ,QAAR;;AAGD;EACC,UAAS,SAAT;EACA,OAAO,IAAP;EACA,QAAQ,MAAR;EACA,YAAY,KAAZ;EACA,QAAQ,gBAAR;EACA,OAAO,KAAP;EACA,KAAK,MAAL;;AAGD;AAAI;AAAI;EACP,QAAQ,QAAR;EACA,aAAY,OAAZ;;AAGD;EACC,aAAY,KAAZ;;AAGD;EACC,QAAQ,WAAR;;AAGD;EACC,QAAQ,WAAR;EACA,QAAQ,KAAR;;AAGD;EACC,SAAS,aAAT;EACA,QAAQ,cAAR;EACA,SAAS,SAAT;EACA,QAAQ,eAAR;EACA,QAAQ,QAAR;EACA,aAAa,KAAb;;AACA;EACC,YAAY,KAAZ;EACA,OAAO,KAAP;;AAIF;EACC,QAAQ,cAAR;EACA,SAAS,EAAT;EACA,YAAY,KAAZ;;AAEA;EACC,QAAQ,WAAR;EACA,SAAS,IAAT;EACA,aAAY,KAAZ;;AAEA;EACC,SAAS,EAAT;;AAGD;EACC,WAAW,KAAX;EACA,gBAAgB,IAAhB;EACA,aAAa,KAAb;;AAGD;EACC,QAAQ,UAAR;;AAOD;EACC,QAAQ,QAAR;;AAEA;EACC,iBAAiB,UAAjB","file":"style.css"}
--------------------------------------------------------------------------------
/js/main.js:
--------------------------------------------------------------------------------
1 | import Game from './game/Game.js'
2 | let Q = {}
3 |
4 | function getMask(x, y, width, height) {
5 | let canvas = document.createElement('canvas')
6 | let context = canvas.getContext('2d')
7 | canvas.width = width
8 | canvas.height = height
9 | document.body.appendChild(canvas);
10 | context.drawImage(Q.spriteImage, x, y, width, height, 0, 0, width, height)
11 | let array = []
12 |
13 | for (let x = 0; x < width; x += 1) {
14 | array[x] = []
15 | for (let y = 0; y < height; y += 1) {
16 | let data = context.getImageData(x, y, 1, 1).data
17 | let value = ' '
18 | if (data[0] === 255) {
19 | value = 'x'
20 | }
21 | array[x][y] = value
22 | }
23 | }
24 |
25 | document.body.removeChild(canvas)
26 |
27 | return array
28 | }
29 |
30 | function spriteImageLoaded() {
31 | // Get masks
32 | Q.masks = []
33 | Q.masks[0] = getMask(464, 1878, 156, 72) // Slime monster
34 | Q.masks[1] = getMask(286, 1834, 168, 116) // Flying saucer
35 | Q.masks[2] = getMask(630, 1870, 104, 80) // Pink Snake
36 | Q.masks[3] = Q.masks[2] // Yellow Snake
37 | Q.masks[4] = getMask(88, 1758, 188, 192) // Dragon
38 | Q.GAME = new Game()
39 | }
40 |
41 | function doubleClick(event) {
42 | if (document.webkitIsFullScreen) {
43 | document.webkitExitFullscreen()
44 | }else {
45 | document.body.webkitRequestFullscreen()
46 | }
47 | }
48 |
49 | function init() {
50 | Q.width = 720
51 | Q.height = 576
52 | Q.spriteImage = new Image()
53 | Q.spriteImage.addEventListener('load', spriteImageLoaded);
54 | Q.spriteImage.src = './assets/sprite.png'
55 | window.addEventListener('dblclick', doubleClick);
56 | }
57 |
58 | window.addEventListener('load', init)
59 |
60 | export default Q
--------------------------------------------------------------------------------
/public/css/style.css:
--------------------------------------------------------------------------------
1 | html,body{margin:0;width:100%;height:100%;display:flex;justify-content:center;align-items:center;background:#000}.click-message{position:absolute;background:#000;width:720px;height:570px;display:flex;justify-content:center;align-items:center;flex-direction:column;gap:20px;color:#fff;font-family:'Roboto Mono',monospace;font-size:30px}#wrapper{position:relative;width:720px;height:570px;flex:none;transform:scaleX(1.65) scaleY(1.25)}#settings{display:none;position:absolute;top:0;left:0;box-sizing:border-box;width:100vw;min-height:100vh;padding:20px;z-index:100;background:#00f;color:#fff;font-family:'Roboto Mono',monospace;font-size:14px;line-height:1.5;}#settings .close-button{position:absolute;top:10px;right:10px;padding:20px;font-size:40px;line-height:20px;cursor:pointer}#settings #vizualizer{position:absolute;width:50%;height:300px;background:#fff;border:10px solid #fff;right:30px;top:200px}#settings h1,#settings h2,#settings h3{margin:0 0 0 0;font-weight:normal}#settings h1{font-weight:bold}#settings section{margin:20px 0 0 0}#settings #data-title{margin:0 0 10px 0;height:20px}#settings .button{display:inline-block;margin:0 10px 10px 0;padding:5px 10px;border:1px solid #fff;cursor:pointer;user-select:none;}#settings .button:active{background:#fff;color:#00f}#settings ul.sound-classes{margin:20px 0 0 20px;padding:0;list-style:none;}#settings ul.sound-classes li{margin:0 0 40px 0;opacity:.6;user-select:none;}#settings ul.sound-classes li:hover{opacity:1}#settings ul.sound-classes li .label{font-size:18px;letter-spacing:1px;font-weight:bold}#settings ul.sound-classes li .counter{margin:0 0 5px 0}#settings ul.sound-classes li .clear{cursor:pointer;}#settings ul.sound-classes li .clear:hover{text-decoration:underline}
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kikk",
3 | "version": "1.0.0",
4 | "main": "js/main.js",
5 | "author": "Lasse Korsgaard",
6 | "license": "MIT",
7 | "browserify": {
8 | "transform": [
9 | [
10 | "babelify",
11 | {
12 | "presets": [
13 | "es2015"
14 | ]
15 | }
16 | ]
17 | ]
18 | },
19 | "scripts": {
20 | "build": "npm run html-copy && npm run style-build && npm run assets-copy && npm run browserify",
21 | "browserify": "browserify js/main.js -o public/bundle.js",
22 | "assets-copy": "cpx \"assets/**/*\" \"public/assets/\" --clean",
23 | "assets-watch": "npm run assets-copy -- --watch",
24 | "html-copy": "cpx \"html/**/*.html\" \"public/\" --clean",
25 | "html-watch": "npm run html-copy -- --watch",
26 | "style-watch": "stylus -m -w -u nib style/main.styl -o public/css/style.css",
27 | "style-build": "stylus -c -u nib style/main.styl -o public/css/style.css",
28 | "eslint": "eslint src",
29 | "stylint": "stylint style",
30 | "budo": "budo js/main.js:bundle.js --port=3000 --live -v --dir=public -o",
31 | "watch": "npm run style-build && concurrently \"npm run assets-watch\" \"npm run html-watch\" \"npm run budo\" \"npm run style-watch\""
32 | },
33 | "pre-commit": [
34 | "eslint",
35 | "stylint"
36 | ],
37 | "dependencies": {
38 | "babel-preset-es2015": "^6.14.0",
39 | "babelify": "^7.3.0",
40 | "browserify": "^14.4.0",
41 | "budo": "^10.0.3",
42 | "concurrently": "^3.1.0",
43 | "cpx": "^1.5.0",
44 | "gsap": "^1.20.2",
45 | "knear": "^0.0.5",
46 | "meyda": "4.0.5",
47 | "ncp": "^2.0.0",
48 | "nib": "^1.1.2",
49 | "stylus": "^0.54.5"
50 | }
51 | }
--------------------------------------------------------------------------------
/js/game/Title.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main'
3 |
4 | class Title {
5 | constructor(type) {
6 | this.counter = 0
7 | this.image = Q.spriteImage
8 | this.type = type
9 |
10 | if (this.type === 'main') {
11 | // this.width = 549
12 | // this.height = 99
13 | // this.x = 85
14 | // this.y = 98
15 | // this.sourceX = 0
16 | // this.sourceY = 1976
17 | // this.sourceWidth = 549
18 | // this.sourceHeight = 99
19 |
20 | this.width = 554
21 | this.height = 70
22 | this.x = 85
23 | this.y = 98
24 | this.sourceX = 626
25 | this.sourceY = 2112
26 | this.sourceWidth = 554
27 | this.sourceHeight = 70
28 | }
29 |
30 | if (this.type === 'jump') {
31 | this.width = 594
32 | this.height = 84
33 | this.x = 85
34 | this.y = 60
35 | this.sourceX = 0
36 | this.sourceY = 2252
37 | this.sourceWidth = 594
38 | this.sourceHeight = 84
39 | }
40 |
41 | if (this.type === 'duck') {
42 | this.width = 600
43 | this.height = 113
44 | this.x = 85
45 | this.y = 60
46 | this.sourceX = 0
47 | this.sourceY = 2091
48 | this.sourceWidth = 600
49 | this.sourceHeight = 113
50 | }
51 |
52 | if (this.type === 'retry') {
53 | this.width = 446
54 | this.height = 112
55 | this.x = 85
56 | this.y = 60
57 | this.sourceX = 0
58 | this.sourceY = 2372
59 | this.sourceWidth = 446
60 | this.sourceHeight = 112
61 | }
62 |
63 | }
64 |
65 | render(context) {
66 | if (Q.debug) {
67 | context.fillStyle = 'rgba(255,0,0,0.1)'
68 | context.fillRect(this.x, this.y, this.width, this.height)
69 | }
70 |
71 |
72 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
73 | }
74 | }
75 |
76 | export default Title
--------------------------------------------------------------------------------
/js/game/Section.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main.js'
3 | import Obstacle from './Obstacle'
4 |
5 | class Section {
6 | constructor(x, noMonsters) {
7 | this.image = Q.spriteImage
8 | this.x = x
9 | this.y = Q.height - 108
10 | this.width = 1400
11 | this.height = 196
12 |
13 | this.sourceX = 428
14 | this.sourceY = 0
15 | this.sourceWidth = 1400
16 | this.sourceHeight = 196
17 |
18 | this.obstacles = []
19 |
20 | let numObstacles = Math.floor(Math.random() * 2) + 1
21 | // let numObstacles = 10
22 | let basePosition = this.x
23 |
24 | if (noMonsters) {
25 | basePosition = 500
26 | numObstacles = 0
27 | }
28 |
29 | for (let index = 0; index < numObstacles; index += 1) {
30 | let type = Math.floor(Math.random() * 5)
31 | // let position = basePosition + Math.floor(Math.random() * (300 * index)) + ((Math.random() * 100) + (300 * index))
32 | // if (position + 150 < this.width) {
33 | // let obstacle = new Obstacle(type, position)
34 | // this.obstacles.push(obstacle)
35 | // }
36 | let position = basePosition + (Math.random() * 150)
37 | // let position = basePosition + 100
38 | if (position + 200 - this.x < this.width - 100) {
39 | let obstacle = new Obstacle(type, position)
40 | this.obstacles.push(obstacle)
41 | basePosition += position + 200 + obstacle.width
42 | }
43 | }
44 | }
45 |
46 | render(context) {
47 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
48 |
49 | this.obstacles.forEach((obstacle) => {
50 | obstacle.x -= Q.speed
51 | obstacle.render(context)
52 | })
53 |
54 | if (this.obstacles[0] && this.obstacles[0].x + this.obstacles[0].width < 0) {
55 | this.obstacles.shift()
56 | }
57 | }
58 | }
59 |
60 | export default Section
--------------------------------------------------------------------------------
/js/game/ScoreBoard.js:
--------------------------------------------------------------------------------
1 | import Q from './../main.js'
2 | import Number from './Number'
3 |
4 |
5 | class ScoreBoard {
6 | constructor() {
7 | this.image = Q.spriteImage
8 |
9 | this.width = 100
10 | this.height = 52
11 |
12 | this.x = 14
13 | this.y = Q.height - this.height - 40
14 |
15 | this.sourceX = 116
16 | this.sourceY = 1444
17 | this.sourceWidth = 100
18 | this.sourceHeight = 52
19 |
20 | this.value = null
21 | this.numbers = []
22 | this.numbers.push(new Number(0))
23 | this.numbers.push(new Number(0))
24 | this.numbers.push(new Number(0))
25 | this.numbers.push(new Number(0))
26 |
27 | // this.numbers[0].set(1)
28 | this.numbers[0].x = this.x + 12
29 | this.numbers[0].y = this.y + 12
30 |
31 | // this.numbers[1].set(2)
32 | this.numbers[1].x = this.x + 12 + (this.numbers[1].width * 1)
33 | this.numbers[1].y = this.y + 12
34 |
35 | // this.numbers[2].set(3)
36 | this.numbers[2].x = this.x + 12 + (this.numbers[2].width * 2)
37 | this.numbers[2].y = this.y + 12
38 |
39 | // this.numbers[3].set(4)
40 | this.numbers[3].x = this.x + 12 + (this.numbers[3].width * 3)
41 | this.numbers[3].y = this.y + 12
42 | }
43 |
44 | set(value) {
45 | this.value = value
46 | let array = value.toString().split('')
47 | while (array.length < 4) {
48 | array.unshift('x')
49 | }
50 |
51 |
52 | for (let index = 0; index < 4; index += 1) {
53 | if (array[3 - index]) {
54 | this.numbers[3 - index].set(array[3 - index])
55 | }
56 | }
57 | }
58 |
59 | clear() {
60 | this.value = null
61 | }
62 |
63 | render(context) {
64 | context.drawImage(this.image, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
65 |
66 | this.numbers.forEach((number) => {
67 | number.render(context)
68 | })
69 | }
70 | }
71 |
72 | export default ScoreBoard
--------------------------------------------------------------------------------
/js/ai/KNN.js:
--------------------------------------------------------------------------------
1 | class KNN {
2 | constructor(topK) {
3 | this.topK = topK;
4 | this.data = [];
5 | }
6 |
7 | distance(arrayA, arrayB) {
8 | let sum = 0;
9 | arrayA.forEach((value, index) => {
10 | sum += Math.pow(value - arrayB[index], 2);
11 | });
12 |
13 | return Math.sqrt(sum);
14 | }
15 |
16 | updateMax(value, array) {
17 | let max = 0;
18 |
19 | array.forEach((object) => {
20 | max = Math.max(max, object.distance);
21 | });
22 |
23 | return max;
24 | }
25 |
26 | mode(array) {
27 | let frequency = {};
28 | let max = 0;
29 | let result = null;
30 |
31 | for (let index = 0; index < array.length; index += 1) {
32 | let id = array[index];
33 | frequency[id] = (frequency[id] || 0) + 1;
34 | if (frequency[id] > max) {
35 | max = frequency[id];
36 | result = id;
37 | }
38 | }
39 |
40 | return result;
41 | }
42 |
43 | predict(value) {
44 | let maxDistance = 0;
45 | let closest = [];
46 | let votes = [];
47 |
48 |
49 | this.data.forEach((object) => {
50 | let entry = {
51 | distance: this.distance(value, object.value),
52 | id: object.id
53 | };
54 |
55 | if (closest.length < this.topK) {
56 | closest.push(entry);
57 | maxDistance = this.updateMax(maxDistance, closest);
58 | }else if (entry.distance < maxDistance) {
59 | let bool = true;
60 | let count = 0;
61 | while (bool) {
62 | if (Number(closest[count].distance) === maxDistance) {
63 | closest.splice(count, 1, entry);
64 | maxDistance = this.updateMax(maxDistance, closest);
65 | bool = false;
66 | }else if (count < closest.length - 1) {
67 | count += 1;
68 | }else {
69 | bool = false;
70 | }
71 | }
72 | }
73 | });
74 |
75 | closest.forEach((entry) => {
76 | votes.push(entry.id);
77 | });
78 |
79 | let prediction = this.mode(votes);
80 |
81 | return {
82 | prediction: prediction,
83 | votes: votes
84 | };
85 | }
86 |
87 | learn(value, id) {
88 | this.data.push({
89 | value: value,
90 | id: id
91 | });
92 | }
93 |
94 | deleteClassData(id) {
95 | for (let index = this.data.length - 1; index >= 0; index -= 1) {
96 | let entry = this.data[index];
97 | if (entry.id === id) {
98 | this.data.splice(index, 1);
99 | }
100 | }
101 | }
102 | }
103 |
104 | export default KNN
--------------------------------------------------------------------------------
/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sound-Controlled Intergalatic Teddy
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |

16 | Click anywhere to start game
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
×
25 |
Settings
26 |
27 |
28 |
29 |
39 |
40 |
43 |
44 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Sound-Controlled Intergalatic Teddy
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |

16 | Click anywhere to start game
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
×
25 |
Settings
26 |
27 |
28 |
29 |
39 |
40 |
43 |
44 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/js/ai/Microphone.js:
--------------------------------------------------------------------------------
1 | import Meyda from 'meyda'
2 |
3 | class Microphone {
4 | constructor(bufferSize, callback) {
5 | if (Reflect.has(window, 'webkitAudioContext') && !Reflect.has(window, 'AudioContext')) {
6 | window.AudioContext = window.webkitAudioContext;
7 | }
8 |
9 | if (Reflect.has(navigator, 'webkitGetUserMedia') && !Reflect.has(navigator, 'getUserMedia')) {
10 | navigator.getUserMedia = navigator.webkitGetUserMedia;
11 | if (!Reflect.has(AudioContext, 'createScriptProcessor')) {
12 | AudioContext.prototype.createScriptProcessor = AudioContext.prototype.createJavaScriptNode;
13 | }
14 | }
15 |
16 | this.context = new AudioContext();
17 |
18 | this.synthesizer = {};
19 | this.synthesizer.out = this.context.createGain();
20 |
21 | this.meyda = Meyda.createMeydaAnalyzer({
22 | audioContext: this.context,
23 | source: this.synthesizer.out,
24 | bufferSize: bufferSize,
25 | featureExtractors: [
26 | 'mfcc',
27 | 'loudness'
28 | ],
29 | callback: callback
30 | });
31 | this.initializeMicrophoneSampling();
32 | }
33 |
34 | initializeMicrophoneSampling() {
35 | let that = this;
36 |
37 | function errorCallback(err) {
38 | throw err;
39 | }
40 |
41 | function successCallback(mediaStream) {
42 | window.mediaStream = mediaStream;
43 | that.source = that.context.createMediaStreamSource(window.mediaStream);
44 | that.meyda.setSource(that.source);
45 | that.meyda.start();
46 |
47 | console.groupEnd();
48 | }
49 |
50 | try {
51 | navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.getUserMedia;
52 |
53 | let constraints = {
54 | video: false,
55 | audio: true
56 | };
57 |
58 | try {
59 | navigator.getUserMedia(constraints, successCallback, errorCallback);
60 | }catch (data) {
61 | let getUserMedia = navigator.mediaDevices.getUserMedia(constraints);
62 | getUserMedia.then(successCallback);
63 | getUserMedia.catch(errorCallback);
64 | }
65 | }catch (data) {
66 | errorCallback();
67 | }
68 | }
69 | }
70 |
71 |
72 | export default Microphone
--------------------------------------------------------------------------------
/js/game/Icon.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main'
3 |
4 | class Icon {
5 | constructor(type) {
6 | this.counter = 0
7 | this.image = Q.spriteImage
8 | this.type = type
9 |
10 | this.canChange = true
11 |
12 | if (type === 'clap') {
13 | this.width = 144
14 | this.height = 204
15 | this.x = 250
16 | this.y = 200
17 | this.sourceX = 1396
18 | this.sourceY = 1754
19 | this.sourceWidth = 144
20 | this.sourceHeight = 204
21 |
22 | this.frame = 0
23 | this.numFrames = 2
24 | this.speed = 10
25 |
26 | }
27 |
28 | if (type === 'say') {
29 | this.width = 155
30 | this.height = 148
31 | this.x = 250
32 | this.y = 250
33 | this.sourceX = 931
34 | this.sourceY = 1812
35 | this.sourceWidth = 155
36 | this.sourceHeight = 148
37 |
38 | this.frame = 0
39 | this.numFrames = 2
40 | this.speed = 10
41 | }
42 | }
43 |
44 | render(context) {
45 | if (Q.debug) {
46 | context.fillStyle = 'rgba(255,0,0,0.1)'
47 | context.fillRect(this.x, this.y, this.width, this.height)
48 | }
49 |
50 |
51 | context.drawImage(this.image, this.sourceX + (this.sourceWidth * this.frame), this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
52 |
53 | if (this.canChange) {
54 | if (this.counter < this.speed) {
55 | this.counter += 1
56 | }else {
57 | this.counter = 0
58 |
59 | if (this.frame < this.numFrames) {
60 | this.frame += 1
61 | }else {
62 | this.frame = 0
63 | if (this.triggered && this.type === 'clap') {
64 | this.canChange = false
65 | this.timer = setTimeout(() => {
66 | this.canChange = true
67 | this.triggered = false
68 | }, 1800)
69 | }
70 |
71 | if (this.triggered && this.type === 'say') {
72 | this.canChange = false
73 | this.timer = setTimeout(() => {
74 | this.canChange = true
75 | this.triggered = false
76 | }, 2200)
77 | }
78 | }
79 |
80 | if (this.type === 'clap' && this.frame === 2) {
81 | Q.player.duck()
82 | if (Q.clapSound) {
83 | Q.clapSound.play()
84 | }
85 | this.triggered = true
86 | }
87 |
88 | if (this.type === 'say' && this.frame === 2) {
89 | Q.player.jump()
90 | if (Q.ohSound) {
91 | Q.ohSound.play()
92 | }
93 | this.triggered = true
94 | }
95 |
96 | }
97 | }
98 | }
99 | }
100 |
101 | export default Icon
--------------------------------------------------------------------------------
/style/main.styl:
--------------------------------------------------------------------------------
1 | html, body {
2 | margin: 0
3 | width: 100%
4 | height: 100%
5 | display: flex
6 | justify-content: center
7 | align-items: center
8 | background: #000
9 | }
10 |
11 |
12 | .click-message {
13 | position absolute;
14 | background black;
15 | width: 720px;
16 | height: 570px;
17 |
18 | display flex;
19 | justify-content: center;
20 | align-items: center;
21 | flex-direction: column;
22 | gap: 20px;
23 | color: #fff;
24 | font-family: 'Roboto Mono', monospace;
25 | font-size: 30px;
26 | }
27 |
28 | #wrapper {
29 | position: relative
30 | width: 720px
31 | height: 570px
32 | flex: none
33 | transform: scaleX(1.65) scaleY(1.25)
34 | }
35 |
36 |
37 |
38 |
39 |
40 | #settings {
41 | display: none
42 | position absolute
43 | top: 0px
44 | left: 0px
45 | box-sizing: border-box
46 | width: 100vw
47 | min-height 100vh
48 | padding: 20px
49 | z-index: 100
50 | background: blue
51 | color: #ffffff
52 | font-family: 'Roboto Mono', monospace
53 | font-size: 14px
54 | line-height: 1.5
55 | // overflow-y: scroll
56 |
57 | .close-button {
58 | position absolute
59 | top: 10px
60 | right: 10px
61 | padding: 20px
62 | font-size: 40px
63 | line-height 20px
64 | cursor: pointer
65 | }
66 |
67 | #vizualizer {
68 | position absolute
69 | width: 50%
70 | height: 300px
71 | background: #fff
72 | border: 10px solid #fff
73 | right: 30px
74 | top: 200px
75 | }
76 |
77 | h1, h2, h3 {
78 | margin: 0 0 0 0
79 | font-weight normal
80 | }
81 |
82 | h1 {
83 | font-weight bold
84 | }
85 |
86 | section {
87 | margin: 20px 0 0 0
88 | }
89 |
90 | #data-title {
91 | margin: 0 0 10px 0
92 | height: 20px
93 | }
94 |
95 | .button {
96 | display: inline-block
97 | margin: 0 10px 10px 0
98 | padding: 5px 10px
99 | border: 1px solid #fff
100 | cursor: pointer
101 | user-select: none
102 | &:active {
103 | background: #fff
104 | color: blue
105 | }
106 | }
107 |
108 | ul.sound-classes {
109 | margin: 20px 0 0 20px
110 | padding: 0
111 | list-style: none
112 |
113 | li {
114 | margin: 0 0 40px 0
115 | opacity: 0.6
116 | user-select none
117 |
118 | &:hover {
119 | opacity: 1
120 | }
121 |
122 | .label {
123 | font-size: 18px
124 | letter-spacing: 1px
125 | font-weight: bold
126 | }
127 |
128 | .counter {
129 | margin: 0 0 5px 0
130 | }
131 |
132 | .train {
133 |
134 | }
135 |
136 | .clear {
137 | cursor: pointer
138 |
139 | &:hover {
140 | text-decoration: underline
141 | }
142 | }
143 | }
144 | }
145 |
146 |
147 | }
--------------------------------------------------------------------------------
/js/game/Player.js:
--------------------------------------------------------------------------------
1 | import TweenMax from "gsap";
2 | import Q from "./../main.js";
3 |
4 | class Player {
5 | constructor() {
6 | this.canChange = true;
7 | this.image = Q.spriteImage;
8 |
9 | this.width = 96;
10 | this.height = 108;
11 |
12 | this.baseX = this.x = 30;
13 | this.baseY = Q.height - this.height - 108;
14 | this.y = this.baseY;
15 | this.offsetY = 0;
16 | this.sourceWidth = 96;
17 | this.sourceHeight = 108;
18 | this.baseFrame = this.frame = 1;
19 | this.numFrames = 1;
20 | this.counter = 0;
21 | this.state = null;
22 |
23 | this.run();
24 | }
25 |
26 | reset() {
27 | if (this.delay) {
28 | this.delay.kill();
29 | }
30 | TweenMax.killTweensOf(this);
31 | // TweenMax.killChildTweensOf(this)
32 | this.canChange = true;
33 | this.x = this.baseX;
34 | this.y = this.baseY;
35 | }
36 |
37 | dead() {
38 | if (this.state !== "dead") {
39 | this.canChange = false;
40 | this.speed = 15;
41 | this.baseFrame = this.frame = 9;
42 | this.numFrames = 4;
43 | this.state = "dead";
44 | this.delay = TweenMax.to(this, 0.3, {
45 | x: this.baseX - 10,
46 | });
47 |
48 | let that = this;
49 | this.delay = TweenMax.to(this, 0.15, {
50 | y: this.baseY - 10,
51 | onComplete: () => {
52 | TweenMax.to(that, 0.15, {
53 | y: that.baseY,
54 | });
55 | that.y = that.baseY;
56 | },
57 | });
58 | }
59 | }
60 |
61 | run() {
62 | if (this.delay) {
63 | this.delay.kill();
64 | }
65 | this.offsetX = 20;
66 | this.offsetY = 0;
67 | this.speed = 5;
68 | this.baseFrame = this.frame = 2;
69 | this.numFrames = 1;
70 | this.state = "running";
71 | }
72 |
73 | jump() {
74 | if (this.canChange) {
75 | if (this.delay) {
76 | this.delay.kill();
77 | }
78 |
79 | this.canChange = false;
80 | this.baseFrame = this.frame = 7;
81 | this.numFrames = 1;
82 | this.speed = 4;
83 | this.state = "jumping";
84 | let that = this;
85 | this.delay = TweenMax.to(that, 0.5, {
86 | y: that.baseY - 240,
87 | repeat: 1,
88 | yoyo: true,
89 | onComplete: () => {
90 | that.run();
91 | that.canChange = true;
92 | },
93 | });
94 | }
95 | }
96 |
97 | duck() {
98 | if (this.canChange) {
99 | if (this.delay) {
100 | this.delay.kill();
101 | }
102 | if (this.state != "ducking") {
103 | this.baseFrame = this.frame = 5;
104 | }
105 | this.offsetY = 34;
106 | this.numFrames = 1;
107 | this.speed = 4;
108 | this.state = "ducking";
109 | this.delay = TweenMax.delayedCall(1.5, () => {
110 | this.run();
111 | });
112 | }
113 | }
114 |
115 | render(context) {
116 | if (Q.debug) {
117 | context.fillStyle = "rgba(0,255,0,0.1)";
118 | context.fillRect(
119 | this.x + this.offsetX,
120 | this.y + this.offsetY,
121 | this.width - this.offsetX,
122 | this.height - this.offsetY
123 | );
124 | }
125 | if (this.counter < this.speed) {
126 | this.counter += 1;
127 | } else {
128 | this.counter = 0;
129 | if (this.frame < this.baseFrame + this.numFrames) {
130 | this.frame += 1;
131 | } else {
132 | this.frame = this.baseFrame;
133 | }
134 | }
135 |
136 | context.drawImage(
137 | this.image,
138 | 0,
139 | this.sourceHeight * (this.frame - 1),
140 | this.sourceWidth,
141 | this.sourceHeight,
142 | this.x,
143 | this.y,
144 | this.width,
145 | this.height
146 | );
147 | }
148 |
149 | pause() {
150 | if (this.delay) {
151 | this.delay.pause();
152 | }
153 | }
154 |
155 | resume() {
156 | if (this.delay) {
157 | this.delay.resume();
158 | }
159 | }
160 | }
161 |
162 | export default Player;
163 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Sound Controlled Intergalactic Teddy
2 |
3 | #### Avoiding space monsters with sounds
4 |
5 | [](https://vimeo.com/241871305)
6 |
7 | [_Sound Controlled Intergalactic Teddy_](https://vimeo.com/241871305) is an infinite runner game where you use your voice and sounds to control Teddy’s movements. If you need to jump over a green slimy alien you say “Ohhh” and to duck you simply clap your hands.
8 |
9 | Using machine learning we have taught the game to understand and differentiate the sounds. For the game to be able to recognise and distinguish the sounds, we trained it by recording a lot of diverse _"ohhh”s_ and _claps_ which made it robust and easy for anyone to play.
10 |
11 | The installation was displayed in Namur, Belgium at [KIKK Festival 2017](https://www.kikk.be/2017/) as a part of [Little.KIKK](https://www.kikk.be/2017/en/little-kikk).
12 |
13 | __[Støj](http://stoj.io)__ is a creative coding studio run by ([Andreas Refsgaard](http://andreasrefsgaard.dk) & [Lasse Korsgaard](http://lassekorsgaard.com))
14 |
15 |
16 | __Game graphics__: [Amalie Kvistgaard](http://amaliekvistgaard.dk)
17 |
18 |
19 | ## Demo
20 | You can play the game here: [demo](https://stoj-kikk.surge.sh/) (Make sure to allow microphone)
21 |
22 |
23 | ## Installation
24 | To install, clone this repository and then run `yarn` in Terminal. This will install all the dependencies. Once these are installed, run `yarn watch` - this will start a local server on your machine and open up the page in your browser and you're ready to play!
25 |
26 | 
27 |
28 | Be sure to allow the browser to use the microphone, otherwise it will not work. Also be aware that due to browser safety issues, this will only work on `localhost` and `https://` domains.
29 |
30 | ## Usage
31 | As per default the machine is trained on _Ohhh_ and _Clap_ sounds.
32 | If you would like to train it to recognize new sounds you can open up the training interface.
33 |
34 | To open the training interface simply hit `Shift + TAB` on your keyboard.
35 |
36 | 
37 |
38 | ### Settings
39 | In the training interface you can load, save and reset training data. You can also control the threshold for how sensitive the microphone should be. if you are attempting to record some new training examples, but find that nothing happens, it could be because the `threshold` is too high. Click `Change Threshold` and set it to a lower number and try again. If the sound is loud enough the sound bars on the right will turn blue.
40 |
41 |
42 | ### Training
43 | You can clear all training data by clicking `Clear All`.
44 |
45 | Now say you want to train the sound that should trigger a jump. Click and hold down the `Train` button under _Jump_ and say the sound a few times (around 10-20 samples should be sufficient). Make sure the sound you're making is short and loud enough for the sound bars to turn completely blue, otherwise the sound is not recorded.
46 |
47 |
48 |
49 |
50 | ## License
51 |
52 | The MIT License (MIT)
53 |
54 | > Copyright 2017 [Støj](http://stoj.io)
55 | >
56 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
57 | >
58 | > The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
59 | >
60 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
61 |
62 | Sound Controlled Intergalactic Teddy makes use of the following libraries:
63 |
64 | - [__KNear__](https://github.com/NathanEpstein/KNear) by [Nathan Epstein](https://github.com/NathanEpstein).
65 | - License: MIT. Copyright (c) 2014 Nathan Epstein
66 | - [__meyda__](https://github.com/meyda/meyda) by [hughrawlinson](https://github.com/hughrawlinson), [nevosegal](https://github.com/nevosegal), [jakubfiala](https://github.com/jakubfiala) & [2xAA](https://github.com/2xaa)
67 | - License: MIT. Copyright (c) 2014 Hugh A. Rawlinson, Nevo Segal, Jakub Fiala
--------------------------------------------------------------------------------
/js/game/Obstacle.js:
--------------------------------------------------------------------------------
1 | import TweenMax from 'gsap'
2 | import Q from './../main'
3 |
4 | class Obstacle {
5 | constructor(index, x) {
6 | this.counter = 0
7 | this.image = Q.spriteImage
8 | this.type = index
9 | this.mask = Q.masks[index]
10 |
11 | if (index === 0) {
12 | // Slime monster
13 | this.width = 156
14 | this.height = 72
15 | this.x = x
16 | this.y = Q.height - 110 - this.height
17 | this.sourceX = 116
18 | this.sourceY = 394
19 | this.sourceWidth = 156
20 | this.sourceHeight = 72
21 |
22 | this.frame = 0
23 | this.numFrames = 3
24 | this.speed = 10
25 | }
26 |
27 |
28 | if (index === 1) {
29 | // Flying saucer
30 | this.width = 168
31 | this.height = 116
32 | this.x = x
33 | this.y = Q.height - 190 - this.height
34 | this.sourceX = 116
35 | this.sourceY = 724
36 | this.sourceWidth = 168
37 | this.sourceHeight = 116
38 |
39 | this.frame = 0
40 | this.numFrames = 2
41 | this.speed = 50
42 |
43 | }
44 |
45 |
46 | if (index === 2) {
47 | // Pink snake
48 | this.width = 104
49 | this.height = 80
50 | this.x = x
51 | this.y = Q.height - 100 - this.height
52 | this.sourceX = 116
53 | this.sourceY = 1082
54 | this.sourceWidth = 104
55 | this.sourceHeight = 80
56 |
57 | this.frame = 0
58 | this.numFrames = 1
59 | this.speed = 20
60 | }
61 |
62 |
63 | if (index === 3) {
64 | // Yellow snake
65 | this.width = 104
66 | this.height = 80
67 | this.x = x
68 | this.y = Q.height - 100 - this.height
69 | this.sourceX = 116
70 | this.sourceY = 1252
71 | this.sourceWidth = 104
72 | this.sourceHeight = 80
73 |
74 | this.frame = 1
75 | this.numFrames = 1
76 | this.speed = 20
77 | }
78 |
79 |
80 |
81 | if (index === 4) {
82 | // Dragon
83 | this.width = 188
84 | this.height = 192
85 | this.x = x
86 | this.y = Q.height - 190 - this.height
87 | this.sourceX = 116
88 | this.sourceY = 0
89 | this.sourceWidth = 188
90 | this.sourceHeight = 192
91 |
92 | this.frame = 0
93 | this.numFrames = 1
94 | this.speed = 20
95 | }
96 |
97 | // this.width *= 0.8
98 | // this.height *= 0.8
99 |
100 | // this.y += (this.height * 0.25)
101 | }
102 |
103 | // getMask(x, y, width, height) {
104 | // let canvas = document.createElement('canvas')
105 | // let context = canvas.getContext('2d')
106 | // canvas.width = width
107 | // canvas.height = height
108 | // document.body.appendChild(canvas);
109 | // context.drawImage(this.image, x, y, width, height, 0, 0, width, height)
110 |
111 |
112 | // let array = []
113 |
114 | // for (let x = 0; x < width; x += 1) {
115 | // array[x] = []
116 | // for (let y = 0; y < height; y += 1) {
117 | // let data = context.getImageData(x, y, 1, 1).data
118 | // let value = ' '
119 | // if (data[0] === 255) {
120 | // value = 'x'
121 | // }
122 | // array[x][y] = value
123 | // }
124 | // }
125 |
126 | // return array
127 | // }
128 |
129 | intersectRect(r1, r2) {
130 | return !(r2.left > r1.right ||
131 | r2.right < r1.left ||
132 | r2.top > r1.bottom ||
133 | r2.bottom < r1.top);
134 | }
135 |
136 | hittest() {
137 | let a = {
138 | x: Q.player.x + Q.player.offsetX,
139 | y: Q.player.y + Q.player.offsetY,
140 | height: Q.player.height,
141 | width: Q.player.width
142 |
143 | }
144 |
145 | let b = this
146 |
147 | let xOverlap = Math.max(0, Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x))
148 | let yOverlap = Math.max(0, Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y))
149 |
150 | let minX = Math.min(a.x, b.x)
151 | let maxX = Math.max(a.x + a.width, b.x + b.width)
152 | let minY = Math.min(a.y, b.y)
153 | let maxY = Math.max(a.y + a.height, b.y + b.height)
154 |
155 | let baseX = 0
156 | let baseY = 0
157 |
158 | if (minX === a.x) {
159 | baseX = 0
160 | }else {
161 | baseX = a.x - b.x
162 | }
163 |
164 | if (minY === a.y) {
165 | baseY = 0
166 | }else {
167 | baseY = a.y - b.y
168 | }
169 |
170 | let found = false
171 |
172 | baseX = Math.floor(baseX)
173 | baseY = Math.floor(baseY)
174 |
175 | for (let x = 0; x < xOverlap; x += 1) {
176 | for (let y = 0; y < yOverlap; y += 1) {
177 | if (!found) {
178 | let char = this.mask[x + baseX][y + baseY]
179 | if (char === 'x') {
180 | found = true
181 | }
182 | }
183 | }
184 | }
185 |
186 | return found
187 |
188 | }
189 |
190 | render(context) {
191 | if (Q.debug) {
192 | context.fillStyle = 'rgba(255,0,0,0.1)'
193 | context.fillRect(this.x, this.y, this.width, this.height)
194 | }
195 |
196 |
197 | context.drawImage(this.image, this.sourceX, this.sourceY + (this.sourceHeight * this.frame), this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height)
198 |
199 | let test = this.intersectRect({
200 | left: this.x,
201 | top: this.y,
202 | bottom: this.y + this.height,
203 | right: this.x + this.width
204 | }, {
205 | left: Q.player.x + Q.player.offsetX,
206 | top: Q.player.y + Q.player.offsetY,
207 | bottom: Q.player.y + Q.player.offsetY + Q.player.height,
208 | right: Q.player.x + Q.player.width - Q.player.offsetX
209 | })
210 |
211 | if (test) {
212 | // Intersecting boundingboxes, check pixels
213 | let pixelHit = this.hittest()
214 | if (pixelHit) {
215 | let event = new CustomEvent('hit', {
216 | detail: {
217 | obstacle: this.type
218 | }
219 | });
220 | window.dispatchEvent(event);
221 | }
222 |
223 | }
224 |
225 | if (this.counter < this.speed) {
226 | this.counter += 1
227 | }else {
228 | this.counter = 0
229 |
230 | if (this.frame < this.numFrames) {
231 | this.frame += 1
232 | }else {
233 | this.frame = 0
234 | }
235 | }
236 | }
237 | }
238 |
239 | export default Obstacle
--------------------------------------------------------------------------------
/public/datasets/knips-weee.json:
--------------------------------------------------------------------------------
1 | {"jump":"[[77.66490563750267,43.26931576549235,17.457467334039528,8.29398159588121,2.742095232875538,0.8920145239545512,-1.2594466973302039,-1.9193657474289016,-3.489789351276039,-2.955327987533718,-3.7774350106132766,-2.6476521406435873,-2.6982124714879885],[46.0350893220093,43.08765998863798,36.83171799152805,26.98530726843738,17.244514266741668,7.905362489093089,1.412717862412332,-3.018783059030082,-4.985241963298916,-5.762052920417998,-6.008024526242345,-6.028462276804292,-6.551425822358412],[22.983376048202445,21.467452380397567,17.809403672368727,12.013572305775504,5.579609564937377,-1.0445835484132613,-6.535798602807099,-10.647044316342223,-12.820428402962351,-13.23758958456438,-12.133676231320498,-9.883275979014401,-7.174472943278231],[20.25185095197685,19.256141145628753,16.837167229910786,12.94647923071989,8.503066072623833,3.7526725190437245,-0.4228964401533377,-3.7935953394874287,-5.896509919598078,-6.766006489913892,-6.493623782683222,-5.294847001014356,-3.630649547625638],[25.77777573479807,24.866137910179162,22.698751083606144,19.07521392137541,14.808586343598646,9.963689174739802,5.322205043834353,1.0182207443880251,-2.4539029604773557,-5.021805084214904,-6.592245070502426,-7.166770950127239,-7.016910055773073],[29.48611965845339,28.232989313427066,25.139997984252265,20.46354635427956,15.13180011139155,9.567457839617475,4.551564493448352,0.31536348712403856,-2.7948889855898758,-4.803493202258357,-5.783153156570793,-5.894295281707811,-5.466681999687042],[27.443722022734164,26.185935248527475,23.190178663313368,18.38419746972289,12.996467074491706,7.273756281297709,2.2496454878125243,-1.9724851597948083,-4.935740081160204,-6.757851604092806,-7.5241922951547355,-7.393988106313734,-6.792575267138919],[26.31649056909737,25.250415584719704,22.887377760036852,18.94218380408716,14.498029386864047,9.500001979881946,4.930735954160663,0.8597153912603345,-2.1586002302147755,-4.216727375415365,-5.3261701609564644,-5.532092777967984,-5.19784645262218],[32.54143397588223,31.320913394698525,28.24401537174983,23.318419350541642,17.543119996108604,11.261656956612372,5.4337744385085704,0.35810664640263024,-3.4503347011616397,-5.9668524904828555,-7.229390812173598,-7.400102924150334,-6.887251241164693],[26.315376222896703,25.25073814019587,22.6078851361557,18.521997864227785,13.959341149927386,9.22703438868521,5.028232613099395,1.414213866383733,-1.3765351937076828,-3.448069352377013,-4.852031476301488,-5.653611066838803,-6.06366501114843],[27.575544359120613,26.526635145675602,23.97261263888534,19.85012828528932,15.1095383024957,9.9727102254694,5.29776142622757,1.2401355686273936,-1.7763138732267931,-3.795628346011222,-4.865569111488615,-5.115762268172067,-4.89570536058467],[25.40189656624443,24.386645703463394,21.94925766707922,18.07012796961546,13.714519297143882,9.071585731920148,4.908312902313121,1.275747026777913,-1.4882255930193362,-3.4622148363321537,-4.684070332296592,-5.2400201262043025,-5.415254132359738],[24.149889321725823,23.0611282120076,20.48874441713667,16.428931174194858,11.944060646975553,7.174386789848308,2.875460839957156,-0.9706680634455327,-3.985100777185535,-6.17436140758967,-7.461919998479458,-7.847125786236934,-7.618373027616737],[39.05011650024608,33.61014622150538,20.80903803628885,5.630104160058375,-5.315283203100886,-10.169728436110677,-9.603612450335032,-7.944804668353581,-8.2745677941766,-11.649168174288778,-15.819250184405016,-17.369845242363215,-14.582130634670376],[21.21931756891081,19.81373296006452,16.493754399537043,12.028664590233802,7.933280742146806,4.471679418344651,1.9014404699211165,-0.30103993609083557,-2.141091551082292,-3.6151067942549147,-4.480579831315051,-4.625389397212765,-4.343034226775403],[26.42246227830219,23.759244463650035,17.36255312472562,9.050951353772131,1.628962815136137,-3.7663512744320915,-6.1922767451750085,-6.5121528318792326,-5.684837272589176,-4.719492981185802,-3.8556856042804726,-3.054903963916847,-2.408941642347615],[28.640187573386356,23.150682319604112,14.61051438935292,6.440174747160295,2.9710811450155235,0.4306361487569102,-1.689039753746484,-5.746015997554854,-9.684752054410563,-12.679569126296716,-11.997580349446611,-7.732998145543243,-3.550162394295412],[30.632219595197967,25.432942297230902,13.124858008280627,-1.8857597033099425,-12.945340426839108,-17.73888235207045,-16.0543687874372,-11.572904570063324,-7.253676499356843,-4.937288693620779,-3.8718945586733877,-2.1218812579080097,1.2202671386776818],[29.07333566320449,26.496942019175197,21.72265741713746,13.65419577559954,5.970576968777379,-1.9740538166902752,-7.715688837444072,-12.293638157545681,-14.645246130077904,-15.422411822042935,-14.593074571253887,-12.163569352384556,-9.223500178754724],[21.348133801113363,20.119841200472923,17.63301439696279,13.373928364316615,8.866942323831733,3.9298479391328995,-0.1523338664381948,-3.52115410364084,-5.590104156091298,-6.664882637072669,-6.868719758743215,-6.356262304098535,-5.67795700064081]]","duck":"[[198.1642085313797,2.0420019745305504,-38.746938030130195,37.80411725314232,5.825257872924882,32.735366267846814,19.21420460542769,-14.843939741760758,-17.146724979385006,-5.560742054240601,11.745977236825384,-3.1601658083465476,-5.962668457937575],[177.23850719630718,5.446132674146088,-57.44944319629864,19.94059603807166,4.422479552733248,11.988157507777487,11.148462616197168,2.201781285929846,-11.952358602613874,0.6172503366860564,7.1125229180537906,-2.765072314086269,-3.6452685778779985],[113.40922890603542,1.7221055427773466,-37.05185192512032,25.780811887851822,20.15539803208129,18.181888914461712,10.367800952016955,3.016277455011855,-11.05910747806136,4.58949087215546,15.58627570751933,-5.853848651754805,-9.048744733288466],[52.43771991878748,5.20328903749718,-4.689834426758967,12.441998740082697,4.377857677065687,16.74707254996891,4.262373091542402,-9.159077535172212,-1.2754747710774175,-1.4922235086184112,4.412835366939598,-5.149292328689051,-8.9597042524109],[23.54982323409058,2.0473253185361737,-11.763290558177175,1.8078913239079255,6.3463608253275945,2.5033803182131775,-2.4573803604488043,-2.9457594450025146,-0.3007612491300673,1.445291080748399,1.9505680220783104,-1.9367984424703335,-3.071240471941103],[56.984243765473366,13.24476397439207,-2.5559036734746177,16.439116688438894,10.956204386064565,14.039101162837458,6.95664607577761,-12.568896088415055,-4.6768186842465,4.0904663438779005,-2.9597012398639873,-4.424672570043586,-1.891322079412265],[143.48390823602676,-12.123917762242382,-17.92232456582372,29.949522615893766,-7.445951436627154,41.237963018388285,24.294086426277858,-9.046392623597834,-13.582161173768156,6.588063720653379,14.29387694816696,9.743980339329505,-10.02623101496038],[48.73152182903141,26.818693091104855,8.988232300288226,15.038277129918287,24.106362068899283,27.940355163901,18.234963894825995,-0.8367740902142619,-2.2449821079968357,7.987049805337327,12.056819446864042,0.6902782220007229,-12.27574473785321],[61.87030660267919,6.867376006616835,-14.546991335610137,11.963791825598706,12.553525141558307,22.74889066028154,16.550952703096222,-7.7893341128100015,-3.6901523985580496,5.22289096336472,13.01445509215743,7.803568914093285,-11.288664823553118],[33.61239472287707,-2.978666212902821,-8.699095491806565,9.289197790030268,2.968725557943181,9.490350618103244,3.2587977435022792,-6.948750496178245,1.4255812365038687,1.823489984830596,1.8673537652124348,0.6629053707662189,-5.4659360004487],[134.31732960045338,-1.3212752278799134,-31.44334674027059,26.054417808928612,23.00669331715962,31.506377940023302,6.868307468444806,0.19584691822629016,-6.0981907786709,7.9142083861724775,7.560198831255139,2.075879138507684,-7.4353672009759935],[91.11921305209398,-10.295979013177451,-35.57184153097577,-3.2929791035394484,-11.59985630064292,18.28916715387521,9.892165585557265,-8.437107394679007,-9.47853717547168,8.764301070419851,4.9201623488965875,-2.379388244706633,-1.640361703621834],[64.24032291397452,-13.804770389002913,-27.923509566771397,9.451745804840185,-6.949987104995344,12.667038055886424,7.168372192929333,-12.028786216762189,-0.7249577524872723,3.913012482128686,4.0952024660514885,-2.938364286130533,-4.386864802064779],[67.26273985393345,-8.784270040237082,-31.257272712093553,4.183400302527695,1.935863354500373,15.288275126921896,16.177214301767346,-14.022458150782711,-13.101043676958247,5.229010007050661,10.47831532190157,5.234943054835469,-4.072090236519672],[121.83491930365562,27.666222837728707,-20.630773023924668,15.94771590254491,15.822080730177483,21.54086204587215,17.406113155729997,-5.20632084590571,-12.280734808956746,-10.500863683296837,0.01959312145201647,-3.6022249924776437,-14.057252717548629],[69.87899569235742,-17.31727096104618,-28.581930044169006,19.25740998589265,-11.35822976660847,-4.169909455825207,17.562488410674163,-2.492949736496214,-4.235697378660345,0.6080750723697145,4.359268327281224,-4.4086469989678365,-2.7977340856661557],[160.63450767099857,13.930900488064067,-34.001723642451616,25.533705712371596,-20.987647724780956,7.483303317801509,17.649796189916643,-5.756838642416709,-1.2300086016872513,-2.8438577620302916,12.009178830237202,-2.382075015005101,-3.9161530345792066],[93.33262585103512,-1.8334969910432999,-36.4168416586987,12.093085202428135,1.58263599704663,14.677927312169162,9.949811456194105,-10.115023135322055,0.6522611980074864,-7.090278805202079,-1.9740504437257116,8.472666338373294,-1.3336875790146157],[36.22474151477218,6.769034306134203,-13.458209958922659,-1.3739135839968262,9.95081958454298,11.604035534471686,5.129421227462105,-6.572932282546369,-2.9034840812729725,1.4665158382247765,0.013644540706566885,0.21455109176153492,-1.0508816927873565],[33.91327319992706,6.974311216710576,-5.864730451508853,4.387793631797542,6.892961200412929,12.271200829583428,16.17863313585371,-0.7720142106226062,-7.428062609841461,2.6420996832899486,9.351930477414589,5.605138718775847,-1.7223327256773815]]"}
--------------------------------------------------------------------------------
/js/game/Game.js:
--------------------------------------------------------------------------------
1 | import Q from "./../main";
2 | import Player from "./Player";
3 | import Moon from "./Moon";
4 | import Backdrop from "./Backdrop";
5 | import Mountain from "./Mountain";
6 | import Section from "./Section";
7 | import Icon from "./Icon";
8 | import Title from "./Title";
9 | import BigNumber from "./BigNumber";
10 | import ScoreBoard from "./ScoreBoard";
11 | import SoundClassifier from "./../ai/AudioClassifier";
12 |
13 | class Game {
14 | constructor() {
15 | this.paused = true;
16 | Q.speed = this.speed = 0;
17 | Q.debug = false;
18 | Q.clapSound = document.querySelector("#clap-sound");
19 | Q.ohSound = document.querySelector("#oh-sound");
20 |
21 | this.speedCounter = 0;
22 | this.resetCounter = 0;
23 | this.counter = 0;
24 | this.scoreBoard = new ScoreBoard();
25 | Q.score = 0;
26 | Q.canvas = this.canvas = document.querySelector("#canvas");
27 | this.canvas.width = Q.width;
28 | this.canvas.height = Q.height;
29 | this.context = this.canvas.getContext("2d");
30 |
31 | Q.classes = {};
32 | Q.allowTraining = false;
33 |
34 | this.clickStart = this.clickStart.bind(this);
35 |
36 | window.addEventListener("click", this.clickStart);
37 | // Q.soundClassifier = new SoundClassifier({
38 | // k: 5,
39 | // threshold: 30
40 | // })
41 | // window.addEventListener('prediction', this.predictionCallback.bind(this));
42 |
43 | // Q.allowMicrophone = false
44 | // Q.player = this.player = new Player()
45 |
46 | // Q.duckIcon = new Icon('clap')
47 | // Q.jumpIcon = new Icon('say')
48 | // Q.title = new Title('main')
49 | // Q.jumpTitle = new Title('jump')
50 | // Q.duckTitle = new Title('duck')
51 | // Q.retryTitle = new Title('retry')
52 | // Q.countdownTitle = new BigNumber(3)
53 | // Q.countdownTitle.x = (720 - 80) / 2
54 | // Q.countdownTitle.y = (570 - 200) / 2
55 |
56 | // Q.showRetry = false
57 | // window.addEventListener('keydown', this.keydown.bind(this))
58 | // window.addEventListener('hit', this.hit.bind(this))
59 |
60 | // Q.timeoutTimer = null
61 | // this.reset(false)
62 |
63 | // this.playing = false
64 | // this.isFirst = 0
65 | }
66 |
67 | clickStart(event) {
68 | window.removeEventListener("click", this.clickStart);
69 | console.log("clickStart");
70 | Q.soundClassifier = new SoundClassifier({
71 | k: 5,
72 | threshold: 30,
73 | });
74 | window.addEventListener("prediction", this.predictionCallback.bind(this));
75 |
76 | Q.allowMicrophone = false;
77 | Q.player = this.player = new Player();
78 |
79 | Q.duckIcon = new Icon("clap");
80 | Q.jumpIcon = new Icon("say");
81 | Q.title = new Title("main");
82 | Q.jumpTitle = new Title("jump");
83 | Q.duckTitle = new Title("duck");
84 | Q.retryTitle = new Title("retry");
85 | Q.countdownTitle = new BigNumber(3);
86 | Q.countdownTitle.x = (720 - 80) / 2;
87 | Q.countdownTitle.y = (570 - 200) / 2;
88 |
89 | Q.showRetry = false;
90 | window.addEventListener("keydown", this.keydown.bind(this));
91 | window.addEventListener("hit", this.hit.bind(this));
92 |
93 | Q.timeoutTimer = null;
94 | this.reset(false);
95 |
96 | this.playing = false;
97 | this.isFirst = 0;
98 | }
99 |
100 | reset(isIntro) {
101 | if (Q.tutorialTimeline) {
102 | Q.tutorialTimeline.kill();
103 | }
104 |
105 | Q.showRetry = false;
106 | Q.showTitle = false;
107 | Q.showDuck = false;
108 | Q.showJump = false;
109 | Q.score = 0;
110 | this.resetCounter = 0;
111 | this.scoreBoard.set(Q.score);
112 | this.dead = false;
113 |
114 | this.backdrops = [];
115 | this.backdrops.push(new Backdrop(0));
116 |
117 | this.mountainsBack = [];
118 | this.mountainsBack.push(new Mountain(0));
119 |
120 | this.mountainsMiddle = [];
121 | this.mountainsMiddle.push(new Mountain(1));
122 |
123 | this.mountainsFront = [];
124 | this.mountainsFront.push(new Mountain(2));
125 |
126 | this.sections = [];
127 | this.sections.push(new Section(0, true));
128 |
129 | Q.player.reset();
130 | Q.score = 0;
131 | if (isIntro === true) {
132 | this.intro();
133 | } else {
134 | Q.isIntro = false;
135 |
136 | if (Q.tutorialTimeline) {
137 | Q.tutorialTimeline.pause();
138 | }
139 | Q.player.run();
140 | this.startGame();
141 | }
142 | }
143 |
144 | tutorialCompleted() {
145 | if (Q.tutorialTimeline) {
146 | Q.tutorialTimeline.kill();
147 | }
148 | Q.showTitle = false;
149 | Q.showDuck = false;
150 | Q.showJump = false;
151 | Q.showRetry = false;
152 |
153 | Q.showScore = true;
154 | Q.isIntro = false;
155 | Q.soundClassifier.enable();
156 | }
157 |
158 | startTutorial() {
159 | Q.soundClassifier.disable();
160 | Q.showRetry = false;
161 |
162 | Q.tutorialTimeline = new TimelineMax({
163 | onComplete: this.tutorialCompleted.bind(this),
164 | });
165 |
166 | Q.showTitle = false;
167 |
168 | Q.tutorialTimeline.to(Q.duckIcon, 4.6, {
169 | delay: 0.5,
170 | onStart: () => {
171 | Q.showDuck = true;
172 | },
173 | onComplete: () => {
174 | Q.showDuck = false;
175 | },
176 | });
177 |
178 | Q.tutorialTimeline.to(Q.jumpIcon, 5.2, {
179 | delay: 0.5,
180 | onStart: () => {
181 | Q.showJump = true;
182 | },
183 | onComplete: () => {
184 | Q.showJump = false;
185 | },
186 | });
187 |
188 | let counter = 3;
189 |
190 | Q.tutorialTimeline.to(Q.countdownTitle, 1, {
191 | delay: 0.2,
192 | repeat: 3,
193 | onRepeat: () => {
194 | counter -= 1;
195 | if (counter < 1) {
196 | Q.countdownTitle.clear();
197 | } else {
198 | Q.countdownTitle.set(counter);
199 | }
200 | },
201 | onStart: () => {
202 | Q.countdownTitle.set(counter);
203 | Q.showCountdown = true;
204 | },
205 | onComplete: () => {
206 | Q.showCountdown = false;
207 | },
208 | });
209 | }
210 |
211 | intro() {
212 | this.reset();
213 | Q.speed = 4;
214 | Q.showScore = false;
215 | Q.player.run();
216 | Q.score = 0;
217 | Q.isIntro = true;
218 | Q.showPlayer = true;
219 | Q.showRetry = false;
220 |
221 | Q.showTitle = true;
222 |
223 | Q.soundClassifier.enable();
224 | if (this.timer) {
225 | cancelAnimationFrame(this.timer);
226 | }
227 | this.timer = requestAnimationFrame(this.render.bind(this));
228 | }
229 |
230 | keydown(event) {
231 | if (event.keyCode === 13) {
232 | this.paused = !this.paused;
233 | if (this.paused) {
234 | this.stopGame();
235 | } else {
236 | this.startGame();
237 | }
238 | } else if (event.keyCode === 32) {
239 | this.reset(false);
240 | } else if (event.keyCode === 38) {
241 | event.preventDefault();
242 | this.player.jump();
243 | } else if (event.keyCode === 40) {
244 | event.preventDefault();
245 | this.player.duck();
246 | }
247 | }
248 |
249 | resetTimeout() {
250 | if (Q.timeoutTimer) {
251 | clearTimeout(Q.timeoutTimer);
252 | }
253 | // Q.timeoutTimer = setTimeout(this.intro.bind(this), 30000)
254 | }
255 |
256 | predictionCallback(event) {
257 | let prediction = event.detail.prediction.prediction;
258 |
259 | this.resetTimeout();
260 |
261 | if (Q.isIntro) {
262 | this.startTutorial();
263 | } else {
264 | if (prediction === "jump") {
265 | this.player.jump();
266 | }
267 |
268 | if (prediction === "duck") {
269 | this.player.duck();
270 | if (this.dead) {
271 | if (this.resetCounter < 1) {
272 | this.resetCounter += 1;
273 | } else {
274 | this.reset(false);
275 | }
276 | }
277 | }
278 | }
279 | }
280 |
281 | pause() {
282 | if (!this.paused) {
283 | this.paused = true;
284 | this.stopGame();
285 | }
286 | }
287 |
288 | unpause() {
289 | if (this.paused) {
290 | this.paused = false;
291 | this.startGame();
292 | }
293 | }
294 |
295 | startGame() {
296 | Q.isIntro = false;
297 | Q.showPlayer = true;
298 | Q.showScore = true;
299 | Q.showDuck = false;
300 | Q.showJump = false;
301 | Q.speed = 4;
302 | Q.player.run();
303 | Q.score = 0;
304 | Q.soundClassifier.disable();
305 |
306 | Q.soundTimer = setTimeout(() => {
307 | Q.soundClassifier.enable();
308 | }, 600);
309 |
310 | this.stopGame();
311 | this.timer = requestAnimationFrame(this.render.bind(this));
312 | this.player.resume();
313 | this.resetTimeout();
314 | }
315 |
316 | stopGame() {
317 | if (this.timer) {
318 | cancelAnimationFrame(this.timer);
319 | }
320 |
321 | this.player.pause();
322 | }
323 |
324 | hit(event) {
325 | Q.speed = 0;
326 | Q.player.dead();
327 | this.dead = true;
328 | Q.showRetry = true;
329 | }
330 |
331 | render() {
332 | this.context.clearRect(0, 0, Q.width, Q.height);
333 |
334 | let removeBackdrop = false;
335 | this.backdrops.forEach((backdrop) => {
336 | backdrop.x -= Q.speed * 0;
337 | backdrop.render(this.context);
338 |
339 | if (backdrop.x + backdrop.width < Q.width && this.backdrops.length < 2) {
340 | this.backdrops.push(new Backdrop(backdrop.x + backdrop.width - 0.5));
341 | } else if (backdrop.x + backdrop.width < 0) {
342 | removeBackdrop = true;
343 | }
344 | });
345 |
346 | if (removeBackdrop) {
347 | this.backdrops.shift();
348 | }
349 |
350 | this.mountainsBack.forEach((mountain) => {
351 | mountain.x -= Q.speed * 0.05;
352 | mountain.render(this.context);
353 | });
354 |
355 | if (
356 | this.mountainsBack.length === 1 &&
357 | this.mountainsBack[0].x + this.mountainsBack[0].width < Q.width
358 | ) {
359 | let mountain = new Mountain(0);
360 | mountain.x = this.mountainsBack[0].x + this.mountainsBack[0].width - 0.5;
361 | this.mountainsBack.push(mountain);
362 | }
363 |
364 | if (this.mountainsBack[0].x + this.mountainsBack[0].width < 0) {
365 | this.mountainsBack.shift();
366 | }
367 |
368 | this.mountainsMiddle.forEach((mountain) => {
369 | mountain.x -= Q.speed * 0.1;
370 | mountain.render(this.context);
371 | });
372 |
373 | if (
374 | this.mountainsMiddle.length === 1 &&
375 | this.mountainsMiddle[0].x + this.mountainsMiddle[0].width < Q.width
376 | ) {
377 | let mountain = new Mountain(1);
378 | mountain.x =
379 | this.mountainsMiddle[0].x + this.mountainsMiddle[0].width - 0.5;
380 | this.mountainsMiddle.push(mountain);
381 | }
382 |
383 | if (this.mountainsMiddle[0].x + this.mountainsMiddle[0].width < 0) {
384 | this.mountainsMiddle.shift();
385 | }
386 |
387 | this.mountainsFront.forEach((mountain) => {
388 | mountain.x -= Q.speed * 0.3;
389 | mountain.render(this.context);
390 | });
391 |
392 | if (
393 | this.mountainsFront.length === 1 &&
394 | this.mountainsFront[0].x + this.mountainsFront[0].width < Q.width
395 | ) {
396 | let mountain = new Mountain(2);
397 | mountain.x =
398 | this.mountainsFront[0].x + this.mountainsFront[0].width - 0.5;
399 | this.mountainsFront.push(mountain);
400 | }
401 |
402 | if (this.mountainsFront[0].x + this.mountainsFront[0].width < 0) {
403 | this.mountainsFront.shift();
404 | }
405 |
406 | let removeSection = false;
407 | this.sections.forEach((section) => {
408 | section.x -= Q.speed;
409 | section.render(this.context);
410 |
411 | if (section.x + section.width < Q.width && this.sections.length < 2) {
412 | this.sections.push(
413 | new Section(section.x + section.width - Q.speed, Q.isIntro)
414 | );
415 | } else if (section.x + section.width < 0) {
416 | removeSection = true;
417 | }
418 | });
419 |
420 | if (removeSection) {
421 | this.sections.shift();
422 | }
423 |
424 | if (Q.showPlayer) {
425 | this.player.render(this.context);
426 | }
427 |
428 | if (!this.dead && this.counter % 10 === 0 && !Q.isIntro) {
429 | Q.score += 1;
430 | this.scoreBoard.set(Q.score);
431 | this.counter = 0;
432 | }
433 |
434 | this.counter += 1;
435 |
436 | if (Q.showScore) {
437 | this.scoreBoard.render(this.context);
438 | }
439 |
440 | if (!this.dead && !Q.isIntro) {
441 | if (this.speedCounter % 120 === 0) {
442 | Q.speed += 0.1;
443 | this.speedCounter = 0;
444 | }
445 | this.speedCounter += 1;
446 | }
447 |
448 | if (Q.showDuck) {
449 | Q.duckIcon.render(this.context);
450 | Q.duckTitle.render(this.context);
451 | }
452 |
453 | if (Q.showJump) {
454 | Q.jumpIcon.render(this.context);
455 | Q.jumpTitle.render(this.context);
456 | }
457 |
458 | if (Q.showTitle) {
459 | Q.title.render(this.context);
460 | }
461 |
462 | if (Q.showCountdown) {
463 | Q.countdownTitle.render(this.context);
464 | }
465 |
466 | if (Q.showRetry) {
467 | Q.retryTitle.render(this.context);
468 | }
469 |
470 | // Debug
471 | if (Q.debug) {
472 | this.context.fillStyle = "red";
473 | this.context.fillRect(0, 0, 40, 40);
474 | this.context.fillStyle = "green";
475 | this.context.fillRect(Q.width - 40, 0, 40, 40);
476 | this.context.fillStyle = "blue";
477 | this.context.fillRect(Q.width - 40, Q.height - 40, 40, 40);
478 | }
479 |
480 | if (!this.renderOnce) {
481 | this.timer = requestAnimationFrame(this.render.bind(this));
482 | } else {
483 | this.renderOnce = false;
484 | }
485 | }
486 | }
487 |
488 | export default Game;
489 |
--------------------------------------------------------------------------------
/js/ai/AudioClassifier.js:
--------------------------------------------------------------------------------
1 | import Meyda from "meyda";
2 | import KNN from "./KNN";
3 | import Q from "./../main";
4 |
5 | class AudioClassifier {
6 | constructor(config) {
7 | let defaultConfig = {
8 | k: 5,
9 | bufferSize: 512,
10 | trainPause: 400,
11 | threshold: 35,
12 | };
13 |
14 | this.config = Object.assign(defaultConfig, config);
15 | this.allowBroadcasting = true;
16 | this.trainingData = [];
17 | this.training = false;
18 | this.allowTraining = false;
19 | this.predicting = false;
20 | this.currentClass = null;
21 |
22 | this.knn = new KNN(this.config.k);
23 | this.setupGUI();
24 |
25 | if (
26 | Reflect.has(window, "webkitAudioContext") &&
27 | !Reflect.has(window, "AudioContext")
28 | ) {
29 | window.AudioContext = window.webkitAudioContext;
30 | }
31 |
32 | if (
33 | Reflect.has(navigator, "webkitGetUserMedia") &&
34 | !Reflect.has(navigator, "getUserMedia")
35 | ) {
36 | navigator.getUserMedia = navigator.webkitGetUserMedia;
37 |
38 | if (!Reflect.has(AudioContext, "createScriptProcessor")) {
39 | AudioContext.prototype.createScriptProcessor =
40 | AudioContext.prototype.createJavaScriptNode;
41 | }
42 | }
43 |
44 | this.context = new AudioContext();
45 |
46 | this.synthesizer = {};
47 | this.synthesizer.out = this.context.createGain();
48 |
49 | let that = this;
50 | this.meyda = Meyda.createMeydaAnalyzer({
51 | audioContext: this.context,
52 | source: this.synthesizer.out,
53 | bufferSize: this.config.bufferSize,
54 | featureExtractors: ["mfcc", "loudness"],
55 | callback: this.audioCallback.bind(that),
56 | });
57 | this.initializeMicrophoneSampling();
58 |
59 | this.renderer = null;
60 | this.peaked = false;
61 | window.addEventListener("resize", this.resize.bind(this));
62 | }
63 |
64 | hideGUI() {
65 | this.hidden = true;
66 | this.element.style.display = "none";
67 | cancelAnimationFrame(this.renderer);
68 | }
69 |
70 | showGUI() {
71 | this.hidden = false;
72 | this.element.style.display = "block";
73 | this.renderer = requestAnimationFrame(this.render.bind(this));
74 | this.resize();
75 | }
76 |
77 | keyDown(event) {
78 | if (event.keyCode === 9 && event.shiftKey) {
79 | event.preventDefault();
80 |
81 | if (this.hidden) {
82 | this.showGUI();
83 | Q.GAME.pause();
84 | } else {
85 | this.hideGUI();
86 | // Q.GAME.unpause()
87 | Q.GAME.reset(false);
88 | }
89 | }
90 | }
91 |
92 | resize() {
93 | this.canvasWidth = this.canvas.width = this.canvas.offsetWidth;
94 | this.canvasHeight = this.canvas.height = this.canvas.offsetHeight;
95 | }
96 |
97 | render() {
98 | this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
99 | this.ctx.fillStyle = this.peaked ? "blue" : "lightblue";
100 |
101 | if (this.visual && this.visual.length > 0) {
102 | let bandWidth = this.canvasWidth / this.visual.length;
103 | this.visual.forEach((value, index) => {
104 | let height = value * (this.canvasHeight * 0.3);
105 | this.ctx.fillRect(
106 | index * bandWidth,
107 | this.canvasHeight - height,
108 | bandWidth + 1,
109 | height
110 | );
111 | });
112 | }
113 | this.renderer = requestAnimationFrame(this.render.bind(this));
114 | }
115 |
116 | changeK() {
117 | let string = prompt("Set K (current value: " + this.knn.topK + ")");
118 | if (string) {
119 | let value = parseInt(string);
120 | if (value > 0 && value < 40) {
121 | this.knn.topK = value;
122 | document.querySelector("#change-k").textContent =
123 | "Change K: " + this.knn.topK;
124 | }
125 | }
126 | }
127 |
128 | changeThreshold() {
129 | let string = prompt(
130 | "Set Threshold (current value: " + this.config.threshold + ")"
131 | );
132 | if (string) {
133 | let value = parseInt(string);
134 | if (value > 0 && value < 200) {
135 | this.config.threshold = value;
136 | document.querySelector("#change-threshold").textContent =
137 | "Change Threshold: " + this.config.threshold;
138 | }
139 | }
140 | }
141 |
142 | trainingButtonDown(event) {
143 | let id = event.currentTarget.parentNode.id;
144 | window.addEventListener("mouseup", this.trainingButtonUpEvent);
145 | this.stopPredicting();
146 | this.startTraining(id);
147 | }
148 |
149 | trainingButtonUp() {
150 | window.removeEventListener("mouseup", this.trainingButtonUpEvent);
151 | this.stopTraining();
152 | this.startPredicting();
153 | }
154 |
155 | confirmClear(event) {
156 | let id = event.currentTarget.parentNode.id;
157 | let test = confirm('Are you sure you want to clear "' + id + '"');
158 | if (test) {
159 | this.clearClass(id);
160 | }
161 | }
162 |
163 | confirmClearAll(event) {
164 | let test = confirm("Are you sure you want to clear all classes");
165 | if (test) {
166 | this.clearAll();
167 | }
168 | }
169 |
170 | setDataSet(json) {
171 | this.clearAll();
172 | this.trainingData = {};
173 | let data = {};
174 |
175 | for (let key in json) {
176 | data[key] = JSON.parse(json[key]);
177 | this.trainingData[key] = [];
178 |
179 | let length = data[key].length;
180 | for (let index = 0; index < length; index += 1) {
181 | this.knn.learn(data[key][index], key);
182 | this.trainingData[key].push(data[key][index]);
183 | }
184 | }
185 | this.updateSamples();
186 | this.stopTraining();
187 | this.startPredicting();
188 | }
189 |
190 | saveDataSet() {
191 | let object = {};
192 | for (let key in this.trainingData) {
193 | object[key] = JSON.stringify(this.trainingData[key]);
194 | }
195 | let string = JSON.stringify(object);
196 | let blob = new Blob([string], { type: "application/json" });
197 | let url = URL.createObjectURL(blob);
198 |
199 | let link = document.createElement("a");
200 | link.href = url;
201 | link.download = "dataset.json";
202 | link.click();
203 | }
204 |
205 | setFileName(name) {
206 | document.querySelector("#data-title").textContent = name;
207 | }
208 |
209 | loadDefaultDataSet() {
210 | let request = new XMLHttpRequest();
211 | let filename = "datasets/default.json?t=" + new Date().getTime();
212 | request.onreadystatechange = () => {
213 | if (request.readyState === 4 && request.status === 200) {
214 | let data = JSON.parse(request.responseText);
215 | this.setDataSet(data);
216 | this.setFileName("default.json");
217 | }
218 | };
219 | request.open("get", filename, true);
220 | request.send();
221 | }
222 |
223 | loadDataSet() {
224 | let input = document.createElement("input");
225 | input.type = "file";
226 | input.addEventListener("change", (event) => {
227 | if (input.files.length > 0) {
228 | let file = input.files[0];
229 | let name = file.name;
230 | let fileReader = new FileReader();
231 | fileReader.onload = (event) => {
232 | let lines = event.target.result;
233 | let data = JSON.parse(lines);
234 | this.setDataSet(data);
235 | this.setFileName(name);
236 | };
237 | fileReader.readAsText(file);
238 | }
239 | });
240 | input.click();
241 | }
242 |
243 | // toggle() {
244 | // this.allowPredicting = !this.allowPredicting
245 | // this.predicting = this.allowPredicting
246 | // if (this.allowPredicting) {
247 | // document.querySelector('#toggle').textContent = 'Disable prediction'
248 | // }else {
249 | // document.querySelector('#toggle').textContent = 'Enable prediction'
250 | // }
251 | // }
252 |
253 | enable() {
254 | this.allowBroadcasting = true;
255 | document.querySelector("#disable").style.opacity = 1;
256 | document.querySelector("#enable").style.opacity = 0.5;
257 | document.querySelector("#enable").textContent = "Enabled";
258 | document.querySelector("#disable").textContent = "Disable";
259 | }
260 |
261 | disable() {
262 | this.allowBroadcasting = false;
263 | document.querySelector("#disable").style.opacity = 0.5;
264 | document.querySelector("#disable").textContent = "Disabled";
265 | document.querySelector("#enable").textContent = "Enable";
266 | document.querySelector("#enable").style.opacity = 1;
267 | }
268 |
269 | setupGUI() {
270 | this.element = document.querySelector("#settings");
271 | this.canvas = document.querySelector("#vizualizer");
272 | this.ctx = this.canvas.getContext("2d");
273 | this.hideGUI();
274 |
275 | let closeButton = document.querySelector(".close-button");
276 | closeButton.addEventListener("click", this.hideGUI.bind(this));
277 |
278 | document
279 | .querySelector("#disable")
280 | .addEventListener("click", this.disable.bind(this));
281 | document
282 | .querySelector("#enable")
283 | .addEventListener("click", this.enable.bind(this));
284 | this.enable();
285 | // document.querySelector('#toggle').addEventListener('click', this.toggle.bind(this));
286 | document
287 | .querySelector("#save")
288 | .addEventListener("click", this.saveDataSet.bind(this));
289 | document
290 | .querySelector("#load")
291 | .addEventListener("click", this.loadDataSet.bind(this));
292 | document.querySelector("#change-k").textContent =
293 | "Change K: " + this.knn.topK;
294 | document
295 | .querySelector("#change-k")
296 | .addEventListener("click", this.changeK.bind(this));
297 |
298 | document.querySelector("#change-threshold").textContent =
299 | "Change Threshold: " + this.config.threshold;
300 | document
301 | .querySelector("#change-threshold")
302 | .addEventListener("click", this.changeThreshold.bind(this));
303 | document
304 | .querySelector("#clear")
305 | .addEventListener("click", this.confirmClearAll.bind(this));
306 | this.trainingButtonUpEvent = this.trainingButtonUp.bind(this);
307 | this.trainingButtons = document.querySelectorAll(".sound-classes a.train");
308 | this.trainingButtons.forEach((button) => {
309 | button.addEventListener("mousedown", this.trainingButtonDown.bind(this));
310 | });
311 |
312 | this.clearButtons = document.querySelectorAll(".sound-classes a.clear");
313 | this.clearButtons.forEach((button) => {
314 | button.addEventListener("click", this.confirmClear.bind(this));
315 | });
316 |
317 | this.loadDefaultDataSet();
318 |
319 | window.addEventListener("keydown", this.keyDown.bind(this));
320 | }
321 |
322 | save() {
323 | let object = {};
324 | for (let key in this.trainingData) {
325 | object[key] = JSON.stringify(this.trainingData[key]);
326 | }
327 | let string = JSON.stringify(object);
328 | }
329 |
330 | clearClass(name) {
331 | this.knn.deleteClassData(name);
332 | this.trainingData[name] = [];
333 | this.updateSamples();
334 | }
335 |
336 | clearAll() {
337 | this.setFileName("");
338 | for (let key in this.trainingData) {
339 | this.clearClass(key);
340 | }
341 | this.trainingData = {};
342 | }
343 |
344 | initializeMicrophoneSampling() {
345 | let that = this;
346 |
347 | function errorCallback(err) {
348 | throw err;
349 | }
350 |
351 | function successCallback(mediaStream) {
352 | window.mediaStream = mediaStream;
353 | that.source = that.context.createMediaStreamSource(window.mediaStream);
354 | that.meyda.setSource(that.source);
355 | that.meyda.start();
356 | }
357 |
358 | try {
359 | navigator.getUserMedia =
360 | navigator.webkitGetUserMedia || navigator.getUserMedia;
361 |
362 | let constraints = {
363 | video: false,
364 | audio: true,
365 | };
366 |
367 | try {
368 | navigator.getUserMedia(constraints, successCallback, errorCallback);
369 | } catch (data) {
370 | let getUserMedia = navigator.mediaDevices.getUserMedia(constraints);
371 | getUserMedia.then(successCallback);
372 | getUserMedia.catch(errorCallback);
373 | }
374 | } catch (data) {
375 | console.log(data);
376 | errorCallback();
377 | }
378 | }
379 |
380 | startTraining(name) {
381 | this.currentClass = name;
382 | if (!this.trainingData[this.currentClass]) {
383 | this.trainingData[this.currentClass] = [];
384 | }
385 | this.training = true;
386 | this.allowTraining = true;
387 | }
388 |
389 | stopTraining() {
390 | this.allowTraining = false;
391 | this.training = false;
392 | }
393 |
394 | startPredicting() {
395 | this.allowPredicting = true;
396 | this.predicting = true;
397 | }
398 |
399 | stopPredicting() {
400 | this.allowPredicting = false;
401 | this.predicting = false;
402 | }
403 |
404 | updateSamples() {
405 | let numSamples = {};
406 |
407 | for (let key in this.trainingData) {
408 | numSamples[key] = this.trainingData[key].length;
409 | }
410 |
411 | this.trainingButtons.forEach((button) => {
412 | let id = button.parentNode.id;
413 | let counter = button.parentNode.children[1].children[0];
414 | counter.textContent = numSamples[id];
415 | });
416 |
417 | let event = new CustomEvent("sample-update", {
418 | detail: {
419 | numSamples: numSamples,
420 | },
421 | });
422 | window.dispatchEvent(event);
423 | }
424 |
425 | audioCallback(data) {
426 | this.visual = data.loudness.specific;
427 |
428 | let peaked = false;
429 | for (let index = 0; index < data.mfcc.length; index += 1) {
430 | if (Math.abs(data.mfcc[index]) >= this.config.threshold) {
431 | peaked = true;
432 | }
433 | }
434 | this.peaked = peaked;
435 |
436 | if (this.training || this.predicting) {
437 | if (peaked) {
438 | if (this.training && this.allowTraining) {
439 | this.knn.learn(data.mfcc, this.currentClass);
440 |
441 | if (!this.trainingData[this.currentClass]) {
442 | this.trainingData[this.currentClass] = [];
443 | }
444 | this.trainingData[this.currentClass].push(data.mfcc);
445 |
446 | this.updateSamples();
447 |
448 | if (this.timer) {
449 | clearTimeout(this.timer);
450 | }
451 | this.allowTraining = false;
452 | this.timer = setTimeout(() => {
453 | this.allowTraining = true;
454 | }, this.config.trainPause);
455 | } else if (this.predicting && this.allowPredicting) {
456 | let prediction = this.knn.predict(data.mfcc);
457 | document.querySelector("#prediction").textContent =
458 | prediction.prediction;
459 | if (this.allowBroadcasting) {
460 | let event = new CustomEvent("prediction", {
461 | detail: { prediction: prediction },
462 | });
463 | window.dispatchEvent(event);
464 | }
465 |
466 | if (this.timer) {
467 | clearTimeout(this.timer);
468 | }
469 | this.allowPredicting = false;
470 | this.timer = setTimeout(() => {
471 | document.querySelector("#prediction").textContent = "";
472 | this.allowPredicting = true;
473 | }, this.config.trainPause);
474 | }
475 | }
476 | }
477 | }
478 | }
479 |
480 | export default AudioClassifier;
481 |
--------------------------------------------------------------------------------
/public/datasets/default_40-40.json:
--------------------------------------------------------------------------------
1 | {"jump":"[[109.49668503645808,55.920622512298806,30.523723363456618,37.667856594526484,9.515314438178693,-9.708903403343983,-37.99551346120515,-25.833127645841348,-2.0169767201334237,-16.69646472354488,-13.698305880633535,5.240435968790032,7.191045363503159],[82.56025137841061,46.06910877750573,15.928368649549206,15.509206448012522,-6.066823301774169,-27.741057583202732,-41.05705926761334,-29.848258130099275,-4.209937603472162,-3.285780109112505,-5.978745793579349,5.424318998561891,9.94781833660738],[85.69063896762236,53.26209380563099,25.14022083550271,26.793462209289945,10.164182460957628,-15.981107363080715,-36.010976888635795,-28.893660335735763,-11.664511860969672,-14.210611712161864,-10.27463052207948,1.0827850718747831,6.7159720994517],[88.04179364673473,55.815066160387126,24.98249977353425,14.705803755874328,-5.875394585333252,-24.10677428374846,-42.094713239806396,-33.17379979484254,-9.41172167626462,-3.2499286289681897,-4.532015115573714,-3.339688279558521,6.242025188081976],[85.44123765934637,65.79872125249913,36.70928705832059,22.399594036805876,9.245798377599876,-7.6643152407468795,-21.940406264221362,-19.946733605400922,-0.7970807857405109,7.5414059780889655,-0.5538965203324273,-2.432301190411529,1.6902736158660043],[82.87239082749875,43.68890300828961,21.41624284879124,21.70701290454408,-11.199896555065042,-22.835789627067292,-30.917808829593625,-30.56400858693412,-8.736158850396892,-2.0579748345159365,-3.4332594955397013,-2.660309694645707,4.415838923297616],[80.2062403236705,53.239394904413814,19.10915643193085,14.595537423172324,5.522099126052732,-23.93505886647565,-42.62335486544609,-28.886757580982955,-9.628631610436509,-9.14009055537748,-9.309647812499499,1.0112085501070962,6.249209362083911],[84.535322048956,62.92396883473762,35.016233224858844,22.772480864669006,5.903241845143496,-10.11054829424767,-21.14357763129125,-22.491300307227267,-3.9434505636729917,8.364231792362467,-0.15140688552084602,-3.693947432252313,2.153719567582259],[81.44327664878074,61.99221684211966,37.418912832173525,27.019061150213137,11.885255303759326,-5.54150775636927,-20.185818084823453,-23.513682574411995,-10.310796531317374,1.2182539436829525,-0.8295614581030488,-3.8510716918705095,2.941964607837534],[80.88555094029653,57.8064467005705,30.852617638726894,23.070772513179772,6.48414856840893,-11.235284531458957,-20.720325990301514,-21.79019970559776,-5.150760718239535,7.68016440917752,-0.6264232719339694,-4.012024120174795,4.533948597425983],[88.6166254088821,40.02664783238239,-0.7278680036708645,10.128676430243885,-0.5764166948932107,-28.63843615878077,-48.2374680627223,-24.98239531121284,6.239232542494255,-2.1805066403305107,-3.8500560545176667,7.44782880130438,8.614895795760816],[88.95872421330569,63.53354510585772,30.20610296020447,15.585182810570018,-3.5800106681590855,-18.595616904854953,-22.208727435225047,-18.121773670260023,0.2817701033103576,12.512373516630355,1.9252249830887591,-7.013012298360269,-3.6011710205531453],[84.43523053686658,50.97347675706917,18.175444359052722,15.269087920872357,-1.8372181108224455,-26.56214771079423,-41.39724451435559,-28.355168383970803,-6.456580071206185,-5.504566557826023,-5.618347489536299,1.4928103879278265,4.08776691313188],[86.25547945643484,61.456389291510426,34.00821302301739,24.747047827909547,4.365667218048517,-13.060272020587774,-21.127938229595014,-21.121071327087726,-2.7663815374858136,8.081447712084374,-1.2696147985781716,-1.6380110480028014,4.3417475138803505],[82.50705946800372,49.94322191566044,12.814815771381955,8.666294067909929,-8.096256839739855,-35.19182953700329,-41.10463173818782,-26.485242445001422,-8.41976736721626,-3.7295475684256676,-8.759697297512165,-5.0129061946900535,1.3496535151114337],[91.21761959855576,77.35855496549169,51.44570426015472,28.809695026832365,11.330571000903255,-0.1917324181582646,-7.425541977559854,-8.56043845437137,-4.672228937488723,-1.3265317017901803,-0.12596582446609597,-0.16431287402866862,-0.017173138238081965],[89.48757732775448,66.16196355659709,37.52480569363568,24.706971666529835,5.5343853782037415,-10.628985075467135,-22.346116261334807,-25.95166498692313,-8.74402922614305,3.6056428623322443,-2.7052427086530617,-4.525200698904599,0.03525800589392544],[83.56886857342215,61.59412258318389,33.919664852930076,22.716702189479207,11.007725450233758,-7.744543471968261,-30.214342462714132,-26.974802867902184,-7.833704261572905,-3.926046299552183,-5.0566002689997225,-4.1908234930431965,2.344587823953147],[80.36043609783155,59.97549342120112,32.17197801786817,20.4642762481839,5.163636760878262,-13.826850613240252,-25.27742086236421,-23.26899369075354,-8.239598661559953,-0.227130437838244,-6.557125925037473,-7.8294417829540945,-0.7271899492559821],[81.435739141265,57.251264809872325,21.535945590157517,4.794739802649482,-8.8559555633458,-27.30623132405005,-38.781234934077474,-26.681682150730495,-5.84972817976942,-2.046506574710958,-6.0040885661536265,-3.258881341320397,3.1673887967130328],[81.39424982946366,61.03945746078174,31.812015213424523,19.776909916732585,5.806140183986494,-14.335489111214091,-24.370251441383804,-17.93108399964915,-1.9197617034105123,6.808914262415498,1.0664536230471056,-1.9780814357697964,4.2897532867391766],[81.36984565545936,67.50626903954735,40.94766751910772,19.42865958195079,2.132280983520647,-15.315188664277882,-26.915246587720652,-22.728553183556894,-9.092862597835394,-0.6998019804598545,-0.5329361800490028,-2.6032946550145613,-2.349737909915707],[81.1319153869972,50.588776192953674,19.313938015859918,18.091099647770864,2.486995801097697,-16.682286345319422,-25.04428757791889,-29.595848778276093,-15.689721490324871,-0.07878509369359155,-8.691004359568481,-12.856797454995068,2.061250499461434],[80.00324144919068,63.674452927927184,41.044532622643146,29.097894520042026,12.73393728584145,-5.708605737584833,-19.15444454210632,-22.32608707698181,-10.38631470431462,0.06524279252993355,-2.2677780633404305,-2.409451484525747,4.621284175673555],[81.01341822082577,70.11902258286067,49.61931225839941,31.974027820109793,16.35486833351133,-0.04224436036870121,-14.935458689063518,-18.112531216120438,-9.705744708136262,-1.7211946138488299,1.497363690138066,2.0592949813027874,2.5506554601945335],[81.4414648364691,60.871830441571404,32.66118854635557,21.16905600889147,5.803436625788172,-14.252648863523346,-25.675556138941666,-23.86584261513472,-9.73960391280717,-0.590071875638576,-7.0148511637533595,-9.315941362460409,0.21094566255529018],[82.27115757069987,45.873034778351595,8.929669061324597,5.780661877282162,-10.515057955375273,-37.3410025954956,-39.6038142450949,-13.238921950401012,-1.811765680686831,-0.4242609015629331,3.3923198490587323,1.136571210123602,0.3747798205863798],[101.62589658005163,58.047996840159875,-0.6651296248186442,-14.853111454882693,-20.64892574468791,-34.558399776717465,-36.76827783959129,-26.003718142131866,-15.257328081643179,-5.709169564676522,1.9663014340159763,10.393388398324142,19.71476716151978],[80.96938503472484,69.21115977719613,47.98405154187606,30.67287409932512,15.591452553547482,0.493126095529331,-11.98216008406746,-13.19151439816315,-5.683939292995347,0.5265073189918519,3.599422716756525,2.9791623323928214,0.7015855305600684],[82.80829321675265,61.5517778075303,34.020762678508966,24.10263230974249,7.768556507834174,-12.945243122498923,-22.36543463089132,-19.404939848392775,-6.06492049632167,4.7951390018652855,0.945839534378299,-3.2791682533548876,2.8028132247443818],[83.23835167193465,63.15511171434492,36.573814699029334,24.45573594472821,7.177738199400015,-11.680104141284597,-22.0596259769056,-19.891401505869943,-5.259824293356672,4.351943135097583,0.4034551175813202,-2.403126384265102,2.0496954723961087],[83.30525613997452,54.654243852965486,21.952036672366436,13.983086015161065,2.700109456849131,-16.54567117320337,-39.35350800982033,-34.652522776041515,-9.980874698533002,-4.171764837501586,-5.551596792914727,-5.421901874155172,-2.4866272900916258],[86.30923125984191,61.18596272544704,31.506690787552998,21.944783765439983,3.476369935455746,-14.068165731371854,-23.243628656604645,-24.413166535971747,-5.585805958899173,7.169454633573282,-2.7270340536660114,-5.6072156165093245,1.9502133364716874],[88.89263370633125,76.1430631240384,51.69208684628147,29.050899595841503,9.749610746880292,-6.174017524205905,-17.735575513798857,-17.267723602263604,-7.341444256474945,0.503017919067063,3.5369737308066234,3.406346927733844,3.0044446630961192],[91.42713737735176,74.56663288841862,48.02511242322079,29.2853728136642,10.362568287665756,-8.10287136043252,-19.843281404918915,-15.432495194325258,-3.24750364537226,1.1276138567619567,1.8331448219750617,0.9299711074584288,-1.5258871364855766],[81.35305859651817,61.07653243692784,34.443109790726965,24.135821694802246,7.778790513266668,-11.592229551585897,-20.45815411358526,-18.919367613350854,-5.792791093287705,4.460014351130335,-1.6454975557978482,-4.7074510830907,3.3134300791753883],[80.4641441646454,46.07478386326031,3.1018790200507467,-3.4966603952666877,-10.61035599460901,-27.841129724793067,-35.85410001392063,-27.156541437518285,-6.490051079709016,7.6432900243108,-0.651115406928802,-9.739268179609535,-0.5173685953747806],[121.41004752716981,74.07019958118956,5.2968758283880675,-20.63045760954949,-26.110091258625605,-28.52167606993706,-28.87723268912591,-20.73089814534322,-7.671398138278978,0.76390054927413,5.350398478895846,4.546745496602966,-1.7046880260114439],[85.94242748867691,62.18908396738849,32.80937736017247,20.595549025574158,0.6631086303809821,-16.295039727827007,-21.595915220731627,-16.318140488844058,1.415502421078077,7.639020846365699,-1.610622609080719,-2.7889928192829134,-0.03986692992470015],[85.33651334293609,48.92274238821307,17.466927097035242,15.682224935924399,-5.874936618032537,-26.455474527761435,-40.22167365018125,-34.44453896536387,-10.991461626543103,-2.3511856393036132,-2.6647551935863873,-0.09037148105184267,9.160060572142854]]","duck":"[[213.72990715503693,20.327600777228024,-16.627182257725433,10.037312180272785,-32.93975304918418,-15.123767029974111,-11.370390891764076,2.9490514234552085,-3.7189745278097295,6.685172340391493,12.486614308446972,3.380704812208394,8.454411053897285],[144.90205335244536,28.6786141718743,-27.940698197257937,16.809577033378705,-6.923293707878069,-10.51229465699062,-2.414599405087854,2.3007541497717177,-7.855888686808247,-11.858647309379545,-4.042300963452248,-6.78279514360814,1.0254833359917375],[166.37749598466326,25.44962549253476,-56.347268222698084,1.447096948208251,-20.673156146126637,-29.27494349832701,-10.376865327020335,3.8702694470923986,-5.404136027556131,-5.767506589868458,9.242721022902451,-0.3443517176262198,-4.192130730883832],[212.8680191040039,29.899820195177817,-70.06551555703979,-19.725099758306435,-24.421283280514004,-7.482703758761916,9.977574570902501,1.7532638866234622,-7.640441016407432,5.306985158643424,2.2268181570512713,-5.665316912675857,-3.950503881729863],[164.06615445017815,2.308549330561373,-63.299657644838724,-2.57994498751231,-1.3800016330641265,-4.805223373273417,0.7323485208707703,8.940351478014009,-13.539992911626285,7.43360008765412,2.179754434764019,-11.643226409230548,-4.012652319617728],[160.5943468878977,17.245557296056102,-77.20105863943212,-7.699110545533931,-16.607145809260142,-5.440264666432563,30.824673118255248,3.331651193437986,-7.773600814589116,-0.030201221550585685,-0.6218507442205966,-2.159388947456443,-7.963118254725149],[101.87539164870395,15.986900131617295,-51.163457719106795,-19.820020092221796,-9.066170746644417,0.19756527470287985,4.147942073844791,5.1103548986888425,9.071081092872427,-2.2725571000939864,-3.884473233356713,1.523924120308789,5.475518939224972],[244.59486734867096,21.165724175708327,-33.58210923700092,13.881452455229628,-26.740836978606865,-18.80706723668529,-18.62612820437212,-6.319027668471481,-2.4963269667899803,-1.5631513452654773,-5.930577100202634,-2.624043710672625,2.194293264968727],[93.9632253915479,58.33593150542007,7.866515534702599,-15.942384912027284,-27.806615374275957,-22.808426446882347,-1.5114872554406855,17.101492073534843,13.974870672731859,5.243137635570929,4.033019193580677,-0.8652116599347046,-3.817333669987109],[86.5259726610966,-20.55268357378687,-32.20558340769798,24.050048838972224,-14.03212700154023,-4.704459272057548,1.8632509371413781,4.9707559245613195,2.1474190684886034,2.4951620537935337,-1.682067680556285,-6.2419225316484015,-1.5229032175130965],[134.56968335434794,47.51912831449276,-32.25305144674159,-25.495617598483495,-18.14792489474181,0.14593606659778813,10.811690659799476,0.7916603903018679,-10.38863934570551,-7.269714682261688,0.42487455255749246,6.22627665669912,7.326474462644878],[233.79699164628983,24.740971882175337,-27.091076735629855,18.367655290305308,-20.293408637588126,-5.445363264065276,-9.280435264491915,9.565132600499494,-13.499098277664183,-5.421583858043869,-5.2063275998238066,-12.845042974082356,-7.68026255885599],[147.9714282527566,22.799775960242332,-58.96148627631604,-13.083007291911285,-22.40238920677378,-12.360097004836767,9.823616124517008,6.700984537764992,3.3646550956222403,2.666239924380014,3.2176474517730296,-0.1804407074094265,-4.309611916205883],[84.23857884702738,-4.579056408666227,-34.41448805666942,15.085033600532887,3.9104696099663605,-3.2153205533849265,-11.516950953409303,8.06433783180823,5.983690238591785,-5.432314587056703,3.757384137625082,-6.863669952064014,1.4493644331197453],[84.13982070796192,11.215880058360051,-37.57521817578528,0.027175688438818103,5.120992960357946,-3.4744170040494082,0.8542483336922032,1.5696104737789016,-0.944287730381493,3.9052994167805624,7.3944440565632,3.0887489589640493,2.2478416886399835],[108.78870451450348,29.788222910414547,-26.51004361656758,1.936490639058925,-6.181162294022369,-7.811297875561433,8.853478718704112,6.99154032332101,-4.155089048266724,-7.507346618420204,-4.335135248261488,-4.102394687887687,-0.11574923883362513],[187.7505221068859,46.91387502781528,-35.138238414669985,-2.746507552262115,-22.983136436747966,-7.638291156335102,1.0111667107360875,0.9224810615636587,-2.2825512565578014,-1.151726240306965,5.5390158565074685,6.133381688067678,6.788512074898497],[85.82041502412176,18.11620844610251,-36.52423933997108,-11.955058859895011,-7.9342834756716085,-8.410522570128228,2.1120498449351714,3.441619226086898,-1.9442785812028702,3.169607656145368,7.117326437077023,-5.735870426900051,-7.042855612998164],[174.11153348907828,22.60170816220315,-38.8767158176484,-7.522074650796314,-29.930861131190976,-9.792728649113608,-6.009043156704836,11.4289763748639,-10.779583529907251,-1.574864806960941,5.143124832929906,0.17390002769571122,8.120922904714469],[237.2187691628933,-8.269195240388235,-57.5390956796284,-14.525483084772551,-15.501257759143291,-1.2207320986389267,-14.522848012971984,-0.5302157825812706,-11.368314816074216,-3.9643249832256164,11.893532517253888,-2.3730086883360437,-2.5957638009958983],[198.91708221286535,39.38966095239249,-33.58295446866396,3.1514481710188478,-45.982844218009966,-24.103836277722902,-19.10454455641383,-7.918505800534733,-6.440172875000268,-16.567345977129726,6.500868410362017,1.3405613496433906,0.6483956274098149],[134.26208274811506,-1.1295369358097502,-55.732116845747846,-7.291308827250756,-7.363357503518128,4.907663473923722,-0.88337864916269,4.486323372210959,4.0291259996142985,-0.24903538394677222,-5.926390856268733,7.752317075584912,0.5761734852368001],[93.55586187238805,-1.8152304422678756,-31.259543444478606,14.70025275492636,-5.215775916668696,-4.578496721881876,-4.121864908976563,-1.4302340717358366,-6.155416980437976,0.36812366087954274,6.13845493570551,-5.420745888527868,-3.64769667989417],[199.47646338306367,18.567104811549832,-80.47188705313019,-10.166733688382426,-14.839174779197,-9.615901899481441,-10.90257013828711,-0.2888199282835119,5.336290258735052,-1.4573757246599284,2.0981838460244635,-1.5261943641840028,1.1788501492506884],[239.01704144477844,3.5335050259190686,-46.03663900943415,6.833234293162469,-14.462750701906334,-2.2838894272228676,-9.731555162441197,-5.58807732733651,-17.94055731418316,-1.597766528923329,2.9089679753794098,-2.436674901498196,-1.6055947659901797],[192.78171277046204,-4.46739562337269,-50.5690110800954,11.895040805603715,-8.048759733319304,-21.55710272189179,-14.6230082152796,-2.9249990474712324,-1.9443193342989928,0.258210547379919,-18.949827888149347,-0.6493375811263327,6.597120044225204],[206.06037655472755,27.93052426926596,-37.534412706336155,17.153552995472452,-15.035612608371078,-10.513983082654017,-4.8300721388443595,9.679743473865992,-1.8107118741625343,-2.5256990659431207,-5.44033264965849,-2.7648798740535874,4.372102993707287],[100.47642800211906,-14.803753303332432,-53.064570995782354,15.839157661459561,12.681721881007249,-14.67507498090633,-2.354097209057182,11.683922659353607,-4.954032603611052,4.534700150000468,-0.5847472489566827,-3.659830491074672,-0.4902948768238673],[94.12884770287201,15.09337529077091,-21.48182294193529,12.82874025232995,-6.25792316170609,-3.890757488251786,-2.3671147481489125,-7.243862070000201,-4.156829720656844,-6.340523667281478,3.7797341952868817,6.5779754804005375,-1.0362143187032673],[95.57812989875674,0.38855874165800475,-50.773422497342025,9.03321029770016,5.6311929571859265,-9.93146003315616,-2.3546806213311586,2.0371606456562574,2.4245174264420855,-2.5787356297922654,-3.3445478848250834,-1.6522756883741077,0.22045108401638147],[113.33015920594335,40.127122174128374,-35.70508089371835,-25.79537383472583,-9.1341284361957,2.3935359844532513,13.307322994841272,11.268105847942897,-0.9869861071347412,-4.844671540920964,0.24826734354149232,3.3269423800941964,3.283146436269289],[126.39723566966131,9.183878773770543,-55.160106493377995,-0.18707239459790365,-13.435519295195537,-7.776044479476531,4.944058377614783,4.355265368943194,3.113424953385149,-1.259569309382424,7.865833402948083,-4.798349841103526,-14.47299674807189],[189.65510255098343,23.950615187162406,-55.56216426561343,-2.9772789638101664,-11.97655179536469,-3.7081028437385033,7.384337972609293,5.040940761964561,3.1509604922446384,2.662823719376978,-2.8427893758566523,-7.056181684386741,-6.192136892606035],[175.46288003213704,21.503150617519474,-53.25227501011244,-6.493723212397822,-21.970610239491286,-11.907455062988728,-3.5085206371572233,8.004755369996975,-4.365710356604317,-10.456922984697666,0.6878756228317848,-5.4583616530371994,-4.701390321733451],[94.05710493854713,10.986088602334364,-36.8425773359097,-0.6202020400841324,-9.716297733382579,-4.070665964547782,6.153486320294905,1.6862524281190292,-1.8494106833481871,-7.061055817001808,-2.1295943532961994,-3.921055341825474,-7.373270719823432],[107.885397400707,7.085577280793136,-47.50943721056687,6.89439984697838,6.341144236745582,1.817151464196414,-0.49898739227524286,-9.448103253001523,-7.333810976880221,-5.274426547522844,-1.4834586493373627,-0.6995371622639457,-0.0870469320629382],[136.8851839825511,12.889653423158057,-37.51394587964225,20.62752642178137,-11.085846341016811,-19.912108469471658,-6.855214691861701,4.138788775234402,0.4201712179018974,-1.3907369030481762,0.4983875541024926,-15.484357158648184,-4.559610093210281],[113.22753800472128,30.2265435053945,-46.677896544776196,-20.30823552502237,1.4830313962673505,-2.248244274240264,-8.465344530318237,-12.395314937639485,-8.553348905218112,7.141353108015711,4.749694180055406,-6.644886192968403,-1.3305373282668456],[135.55295725504402,19.62067880424298,-46.73367336523344,-6.741187917303103,-20.24097182251455,-7.597630767714392,0.6729992201391498,-1.4252591360334188,-4.9498308144143905,-4.965639349265447,9.575336473052682,7.731639002819358,4.471520436861803],[150.25881531101186,21.802064338814798,-44.29274109687284,-4.235352830060731,-17.666143446644888,4.9798391833912055,-1.574840791115542,-6.854201532454216,-1.8143245686618155,-4.957256272327222,-0.6412573771044269,-6.95491703313055,-4.444404538369984]]"}
--------------------------------------------------------------------------------
/public/datasets/default.json:
--------------------------------------------------------------------------------
1 | {"jump":"[[109.49668503645808,55.920622512298806,30.523723363456618,37.667856594526484,9.515314438178693,-9.708903403343983,-37.99551346120515,-25.833127645841348,-2.0169767201334237,-16.69646472354488,-13.698305880633535,5.240435968790032,7.191045363503159],[82.56025137841061,46.06910877750573,15.928368649549206,15.509206448012522,-6.066823301774169,-27.741057583202732,-41.05705926761334,-29.848258130099275,-4.209937603472162,-3.285780109112505,-5.978745793579349,5.424318998561891,9.94781833660738],[85.69063896762236,53.26209380563099,25.14022083550271,26.793462209289945,10.164182460957628,-15.981107363080715,-36.010976888635795,-28.893660335735763,-11.664511860969672,-14.210611712161864,-10.27463052207948,1.0827850718747831,6.7159720994517],[88.04179364673473,55.815066160387126,24.98249977353425,14.705803755874328,-5.875394585333252,-24.10677428374846,-42.094713239806396,-33.17379979484254,-9.41172167626462,-3.2499286289681897,-4.532015115573714,-3.339688279558521,6.242025188081976],[85.44123765934637,65.79872125249913,36.70928705832059,22.399594036805876,9.245798377599876,-7.6643152407468795,-21.940406264221362,-19.946733605400922,-0.7970807857405109,7.5414059780889655,-0.5538965203324273,-2.432301190411529,1.6902736158660043],[82.87239082749875,43.68890300828961,21.41624284879124,21.70701290454408,-11.199896555065042,-22.835789627067292,-30.917808829593625,-30.56400858693412,-8.736158850396892,-2.0579748345159365,-3.4332594955397013,-2.660309694645707,4.415838923297616],[80.2062403236705,53.239394904413814,19.10915643193085,14.595537423172324,5.522099126052732,-23.93505886647565,-42.62335486544609,-28.886757580982955,-9.628631610436509,-9.14009055537748,-9.309647812499499,1.0112085501070962,6.249209362083911],[84.535322048956,62.92396883473762,35.016233224858844,22.772480864669006,5.903241845143496,-10.11054829424767,-21.14357763129125,-22.491300307227267,-3.9434505636729917,8.364231792362467,-0.15140688552084602,-3.693947432252313,2.153719567582259],[81.44327664878074,61.99221684211966,37.418912832173525,27.019061150213137,11.885255303759326,-5.54150775636927,-20.185818084823453,-23.513682574411995,-10.310796531317374,1.2182539436829525,-0.8295614581030488,-3.8510716918705095,2.941964607837534],[80.88555094029653,57.8064467005705,30.852617638726894,23.070772513179772,6.48414856840893,-11.235284531458957,-20.720325990301514,-21.79019970559776,-5.150760718239535,7.68016440917752,-0.6264232719339694,-4.012024120174795,4.533948597425983],[88.6166254088821,40.02664783238239,-0.7278680036708645,10.128676430243885,-0.5764166948932107,-28.63843615878077,-48.2374680627223,-24.98239531121284,6.239232542494255,-2.1805066403305107,-3.8500560545176667,7.44782880130438,8.614895795760816],[88.95872421330569,63.53354510585772,30.20610296020447,15.585182810570018,-3.5800106681590855,-18.595616904854953,-22.208727435225047,-18.121773670260023,0.2817701033103576,12.512373516630355,1.9252249830887591,-7.013012298360269,-3.6011710205531453],[84.43523053686658,50.97347675706917,18.175444359052722,15.269087920872357,-1.8372181108224455,-26.56214771079423,-41.39724451435559,-28.355168383970803,-6.456580071206185,-5.504566557826023,-5.618347489536299,1.4928103879278265,4.08776691313188],[86.25547945643484,61.456389291510426,34.00821302301739,24.747047827909547,4.365667218048517,-13.060272020587774,-21.127938229595014,-21.121071327087726,-2.7663815374858136,8.081447712084374,-1.2696147985781716,-1.6380110480028014,4.3417475138803505],[82.50705946800372,49.94322191566044,12.814815771381955,8.666294067909929,-8.096256839739855,-35.19182953700329,-41.10463173818782,-26.485242445001422,-8.41976736721626,-3.7295475684256676,-8.759697297512165,-5.0129061946900535,1.3496535151114337],[91.21761959855576,77.35855496549169,51.44570426015472,28.809695026832365,11.330571000903255,-0.1917324181582646,-7.425541977559854,-8.56043845437137,-4.672228937488723,-1.3265317017901803,-0.12596582446609597,-0.16431287402866862,-0.017173138238081965],[89.48757732775448,66.16196355659709,37.52480569363568,24.706971666529835,5.5343853782037415,-10.628985075467135,-22.346116261334807,-25.95166498692313,-8.74402922614305,3.6056428623322443,-2.7052427086530617,-4.525200698904599,0.03525800589392544],[83.56886857342215,61.59412258318389,33.919664852930076,22.716702189479207,11.007725450233758,-7.744543471968261,-30.214342462714132,-26.974802867902184,-7.833704261572905,-3.926046299552183,-5.0566002689997225,-4.1908234930431965,2.344587823953147],[80.36043609783155,59.97549342120112,32.17197801786817,20.4642762481839,5.163636760878262,-13.826850613240252,-25.27742086236421,-23.26899369075354,-8.239598661559953,-0.227130437838244,-6.557125925037473,-7.8294417829540945,-0.7271899492559821],[81.435739141265,57.251264809872325,21.535945590157517,4.794739802649482,-8.8559555633458,-27.30623132405005,-38.781234934077474,-26.681682150730495,-5.84972817976942,-2.046506574710958,-6.0040885661536265,-3.258881341320397,3.1673887967130328],[81.39424982946366,61.03945746078174,31.812015213424523,19.776909916732585,5.806140183986494,-14.335489111214091,-24.370251441383804,-17.93108399964915,-1.9197617034105123,6.808914262415498,1.0664536230471056,-1.9780814357697964,4.2897532867391766],[81.36984565545936,67.50626903954735,40.94766751910772,19.42865958195079,2.132280983520647,-15.315188664277882,-26.915246587720652,-22.728553183556894,-9.092862597835394,-0.6998019804598545,-0.5329361800490028,-2.6032946550145613,-2.349737909915707],[81.1319153869972,50.588776192953674,19.313938015859918,18.091099647770864,2.486995801097697,-16.682286345319422,-25.04428757791889,-29.595848778276093,-15.689721490324871,-0.07878509369359155,-8.691004359568481,-12.856797454995068,2.061250499461434],[80.00324144919068,63.674452927927184,41.044532622643146,29.097894520042026,12.73393728584145,-5.708605737584833,-19.15444454210632,-22.32608707698181,-10.38631470431462,0.06524279252993355,-2.2677780633404305,-2.409451484525747,4.621284175673555],[81.01341822082577,70.11902258286067,49.61931225839941,31.974027820109793,16.35486833351133,-0.04224436036870121,-14.935458689063518,-18.112531216120438,-9.705744708136262,-1.7211946138488299,1.497363690138066,2.0592949813027874,2.5506554601945335],[81.4414648364691,60.871830441571404,32.66118854635557,21.16905600889147,5.803436625788172,-14.252648863523346,-25.675556138941666,-23.86584261513472,-9.73960391280717,-0.590071875638576,-7.0148511637533595,-9.315941362460409,0.21094566255529018],[82.27115757069987,45.873034778351595,8.929669061324597,5.780661877282162,-10.515057955375273,-37.3410025954956,-39.6038142450949,-13.238921950401012,-1.811765680686831,-0.4242609015629331,3.3923198490587323,1.136571210123602,0.3747798205863798],[101.62589658005163,58.047996840159875,-0.6651296248186442,-14.853111454882693,-20.64892574468791,-34.558399776717465,-36.76827783959129,-26.003718142131866,-15.257328081643179,-5.709169564676522,1.9663014340159763,10.393388398324142,19.71476716151978],[80.96938503472484,69.21115977719613,47.98405154187606,30.67287409932512,15.591452553547482,0.493126095529331,-11.98216008406746,-13.19151439816315,-5.683939292995347,0.5265073189918519,3.599422716756525,2.9791623323928214,0.7015855305600684],[82.80829321675265,61.5517778075303,34.020762678508966,24.10263230974249,7.768556507834174,-12.945243122498923,-22.36543463089132,-19.404939848392775,-6.06492049632167,4.7951390018652855,0.945839534378299,-3.2791682533548876,2.8028132247443818],[83.23835167193465,63.15511171434492,36.573814699029334,24.45573594472821,7.177738199400015,-11.680104141284597,-22.0596259769056,-19.891401505869943,-5.259824293356672,4.351943135097583,0.4034551175813202,-2.403126384265102,2.0496954723961087],[83.30525613997452,54.654243852965486,21.952036672366436,13.983086015161065,2.700109456849131,-16.54567117320337,-39.35350800982033,-34.652522776041515,-9.980874698533002,-4.171764837501586,-5.551596792914727,-5.421901874155172,-2.4866272900916258],[86.30923125984191,61.18596272544704,31.506690787552998,21.944783765439983,3.476369935455746,-14.068165731371854,-23.243628656604645,-24.413166535971747,-5.585805958899173,7.169454633573282,-2.7270340536660114,-5.6072156165093245,1.9502133364716874],[88.89263370633125,76.1430631240384,51.69208684628147,29.050899595841503,9.749610746880292,-6.174017524205905,-17.735575513798857,-17.267723602263604,-7.341444256474945,0.503017919067063,3.5369737308066234,3.406346927733844,3.0044446630961192],[91.42713737735176,74.56663288841862,48.02511242322079,29.2853728136642,10.362568287665756,-8.10287136043252,-19.843281404918915,-15.432495194325258,-3.24750364537226,1.1276138567619567,1.8331448219750617,0.9299711074584288,-1.5258871364855766],[81.35305859651817,61.07653243692784,34.443109790726965,24.135821694802246,7.778790513266668,-11.592229551585897,-20.45815411358526,-18.919367613350854,-5.792791093287705,4.460014351130335,-1.6454975557978482,-4.7074510830907,3.3134300791753883],[80.4641441646454,46.07478386326031,3.1018790200507467,-3.4966603952666877,-10.61035599460901,-27.841129724793067,-35.85410001392063,-27.156541437518285,-6.490051079709016,7.6432900243108,-0.651115406928802,-9.739268179609535,-0.5173685953747806],[121.41004752716981,74.07019958118956,5.2968758283880675,-20.63045760954949,-26.110091258625605,-28.52167606993706,-28.87723268912591,-20.73089814534322,-7.671398138278978,0.76390054927413,5.350398478895846,4.546745496602966,-1.7046880260114439],[85.94242748867691,62.18908396738849,32.80937736017247,20.595549025574158,0.6631086303809821,-16.295039727827007,-21.595915220731627,-16.318140488844058,1.415502421078077,7.639020846365699,-1.610622609080719,-2.7889928192829134,-0.03986692992470015],[85.33651334293609,48.92274238821307,17.466927097035242,15.682224935924399,-5.874936618032537,-26.455474527761435,-40.22167365018125,-34.44453896536387,-10.991461626543103,-2.3511856393036132,-2.6647551935863873,-0.09037148105184267,9.160060572142854]]","duck":"[[213.72990715503693,20.327600777228024,-16.627182257725433,10.037312180272785,-32.93975304918418,-15.123767029974111,-11.370390891764076,2.9490514234552085,-3.7189745278097295,6.685172340391493,12.486614308446972,3.380704812208394,8.454411053897285],[144.90205335244536,28.6786141718743,-27.940698197257937,16.809577033378705,-6.923293707878069,-10.51229465699062,-2.414599405087854,2.3007541497717177,-7.855888686808247,-11.858647309379545,-4.042300963452248,-6.78279514360814,1.0254833359917375],[166.37749598466326,25.44962549253476,-56.347268222698084,1.447096948208251,-20.673156146126637,-29.27494349832701,-10.376865327020335,3.8702694470923986,-5.404136027556131,-5.767506589868458,9.242721022902451,-0.3443517176262198,-4.192130730883832],[212.8680191040039,29.899820195177817,-70.06551555703979,-19.725099758306435,-24.421283280514004,-7.482703758761916,9.977574570902501,1.7532638866234622,-7.640441016407432,5.306985158643424,2.2268181570512713,-5.665316912675857,-3.950503881729863],[164.06615445017815,2.308549330561373,-63.299657644838724,-2.57994498751231,-1.3800016330641265,-4.805223373273417,0.7323485208707703,8.940351478014009,-13.539992911626285,7.43360008765412,2.179754434764019,-11.643226409230548,-4.012652319617728],[160.5943468878977,17.245557296056102,-77.20105863943212,-7.699110545533931,-16.607145809260142,-5.440264666432563,30.824673118255248,3.331651193437986,-7.773600814589116,-0.030201221550585685,-0.6218507442205966,-2.159388947456443,-7.963118254725149],[101.87539164870395,15.986900131617295,-51.163457719106795,-19.820020092221796,-9.066170746644417,0.19756527470287985,4.147942073844791,5.1103548986888425,9.071081092872427,-2.2725571000939864,-3.884473233356713,1.523924120308789,5.475518939224972],[244.59486734867096,21.165724175708327,-33.58210923700092,13.881452455229628,-26.740836978606865,-18.80706723668529,-18.62612820437212,-6.319027668471481,-2.4963269667899803,-1.5631513452654773,-5.930577100202634,-2.624043710672625,2.194293264968727],[93.9632253915479,58.33593150542007,7.866515534702599,-15.942384912027284,-27.806615374275957,-22.808426446882347,-1.5114872554406855,17.101492073534843,13.974870672731859,5.243137635570929,4.033019193580677,-0.8652116599347046,-3.817333669987109],[86.5259726610966,-20.55268357378687,-32.20558340769798,24.050048838972224,-14.03212700154023,-4.704459272057548,1.8632509371413781,4.9707559245613195,2.1474190684886034,2.4951620537935337,-1.682067680556285,-6.2419225316484015,-1.5229032175130965],[134.56968335434794,47.51912831449276,-32.25305144674159,-25.495617598483495,-18.14792489474181,0.14593606659778813,10.811690659799476,0.7916603903018679,-10.38863934570551,-7.269714682261688,0.42487455255749246,6.22627665669912,7.326474462644878],[233.79699164628983,24.740971882175337,-27.091076735629855,18.367655290305308,-20.293408637588126,-5.445363264065276,-9.280435264491915,9.565132600499494,-13.499098277664183,-5.421583858043869,-5.2063275998238066,-12.845042974082356,-7.68026255885599],[147.9714282527566,22.799775960242332,-58.96148627631604,-13.083007291911285,-22.40238920677378,-12.360097004836767,9.823616124517008,6.700984537764992,3.3646550956222403,2.666239924380014,3.2176474517730296,-0.1804407074094265,-4.309611916205883],[84.23857884702738,-4.579056408666227,-34.41448805666942,15.085033600532887,3.9104696099663605,-3.2153205533849265,-11.516950953409303,8.06433783180823,5.983690238591785,-5.432314587056703,3.757384137625082,-6.863669952064014,1.4493644331197453],[84.13982070796192,11.215880058360051,-37.57521817578528,0.027175688438818103,5.120992960357946,-3.4744170040494082,0.8542483336922032,1.5696104737789016,-0.944287730381493,3.9052994167805624,7.3944440565632,3.0887489589640493,2.2478416886399835],[108.78870451450348,29.788222910414547,-26.51004361656758,1.936490639058925,-6.181162294022369,-7.811297875561433,8.853478718704112,6.99154032332101,-4.155089048266724,-7.507346618420204,-4.335135248261488,-4.102394687887687,-0.11574923883362513],[187.7505221068859,46.91387502781528,-35.138238414669985,-2.746507552262115,-22.983136436747966,-7.638291156335102,1.0111667107360875,0.9224810615636587,-2.2825512565578014,-1.151726240306965,5.5390158565074685,6.133381688067678,6.788512074898497],[85.82041502412176,18.11620844610251,-36.52423933997108,-11.955058859895011,-7.9342834756716085,-8.410522570128228,2.1120498449351714,3.441619226086898,-1.9442785812028702,3.169607656145368,7.117326437077023,-5.735870426900051,-7.042855612998164],[174.11153348907828,22.60170816220315,-38.8767158176484,-7.522074650796314,-29.930861131190976,-9.792728649113608,-6.009043156704836,11.4289763748639,-10.779583529907251,-1.574864806960941,5.143124832929906,0.17390002769571122,8.120922904714469],[237.2187691628933,-8.269195240388235,-57.5390956796284,-14.525483084772551,-15.501257759143291,-1.2207320986389267,-14.522848012971984,-0.5302157825812706,-11.368314816074216,-3.9643249832256164,11.893532517253888,-2.3730086883360437,-2.5957638009958983],[198.91708221286535,39.38966095239249,-33.58295446866396,3.1514481710188478,-45.982844218009966,-24.103836277722902,-19.10454455641383,-7.918505800534733,-6.440172875000268,-16.567345977129726,6.500868410362017,1.3405613496433906,0.6483956274098149],[134.26208274811506,-1.1295369358097502,-55.732116845747846,-7.291308827250756,-7.363357503518128,4.907663473923722,-0.88337864916269,4.486323372210959,4.0291259996142985,-0.24903538394677222,-5.926390856268733,7.752317075584912,0.5761734852368001],[93.55586187238805,-1.8152304422678756,-31.259543444478606,14.70025275492636,-5.215775916668696,-4.578496721881876,-4.121864908976563,-1.4302340717358366,-6.155416980437976,0.36812366087954274,6.13845493570551,-5.420745888527868,-3.64769667989417],[199.47646338306367,18.567104811549832,-80.47188705313019,-10.166733688382426,-14.839174779197,-9.615901899481441,-10.90257013828711,-0.2888199282835119,5.336290258735052,-1.4573757246599284,2.0981838460244635,-1.5261943641840028,1.1788501492506884],[239.01704144477844,3.5335050259190686,-46.03663900943415,6.833234293162469,-14.462750701906334,-2.2838894272228676,-9.731555162441197,-5.58807732733651,-17.94055731418316,-1.597766528923329,2.9089679753794098,-2.436674901498196,-1.6055947659901797],[192.78171277046204,-4.46739562337269,-50.5690110800954,11.895040805603715,-8.048759733319304,-21.55710272189179,-14.6230082152796,-2.9249990474712324,-1.9443193342989928,0.258210547379919,-18.949827888149347,-0.6493375811263327,6.597120044225204],[206.06037655472755,27.93052426926596,-37.534412706336155,17.153552995472452,-15.035612608371078,-10.513983082654017,-4.8300721388443595,9.679743473865992,-1.8107118741625343,-2.5256990659431207,-5.44033264965849,-2.7648798740535874,4.372102993707287],[100.47642800211906,-14.803753303332432,-53.064570995782354,15.839157661459561,12.681721881007249,-14.67507498090633,-2.354097209057182,11.683922659353607,-4.954032603611052,4.534700150000468,-0.5847472489566827,-3.659830491074672,-0.4902948768238673],[94.12884770287201,15.09337529077091,-21.48182294193529,12.82874025232995,-6.25792316170609,-3.890757488251786,-2.3671147481489125,-7.243862070000201,-4.156829720656844,-6.340523667281478,3.7797341952868817,6.5779754804005375,-1.0362143187032673],[95.57812989875674,0.38855874165800475,-50.773422497342025,9.03321029770016,5.6311929571859265,-9.93146003315616,-2.3546806213311586,2.0371606456562574,2.4245174264420855,-2.5787356297922654,-3.3445478848250834,-1.6522756883741077,0.22045108401638147],[113.33015920594335,40.127122174128374,-35.70508089371835,-25.79537383472583,-9.1341284361957,2.3935359844532513,13.307322994841272,11.268105847942897,-0.9869861071347412,-4.844671540920964,0.24826734354149232,3.3269423800941964,3.283146436269289],[126.39723566966131,9.183878773770543,-55.160106493377995,-0.18707239459790365,-13.435519295195537,-7.776044479476531,4.944058377614783,4.355265368943194,3.113424953385149,-1.259569309382424,7.865833402948083,-4.798349841103526,-14.47299674807189],[189.65510255098343,23.950615187162406,-55.56216426561343,-2.9772789638101664,-11.97655179536469,-3.7081028437385033,7.384337972609293,5.040940761964561,3.1509604922446384,2.662823719376978,-2.8427893758566523,-7.056181684386741,-6.192136892606035],[175.46288003213704,21.503150617519474,-53.25227501011244,-6.493723212397822,-21.970610239491286,-11.907455062988728,-3.5085206371572233,8.004755369996975,-4.365710356604317,-10.456922984697666,0.6878756228317848,-5.4583616530371994,-4.701390321733451],[94.05710493854713,10.986088602334364,-36.8425773359097,-0.6202020400841324,-9.716297733382579,-4.070665964547782,6.153486320294905,1.6862524281190292,-1.8494106833481871,-7.061055817001808,-2.1295943532961994,-3.921055341825474,-7.373270719823432],[107.885397400707,7.085577280793136,-47.50943721056687,6.89439984697838,6.341144236745582,1.817151464196414,-0.49898739227524286,-9.448103253001523,-7.333810976880221,-5.274426547522844,-1.4834586493373627,-0.6995371622639457,-0.0870469320629382],[136.8851839825511,12.889653423158057,-37.51394587964225,20.62752642178137,-11.085846341016811,-19.912108469471658,-6.855214691861701,4.138788775234402,0.4201712179018974,-1.3907369030481762,0.4983875541024926,-15.484357158648184,-4.559610093210281],[113.22753800472128,30.2265435053945,-46.677896544776196,-20.30823552502237,1.4830313962673505,-2.248244274240264,-8.465344530318237,-12.395314937639485,-8.553348905218112,7.141353108015711,4.749694180055406,-6.644886192968403,-1.3305373282668456],[135.55295725504402,19.62067880424298,-46.73367336523344,-6.741187917303103,-20.24097182251455,-7.597630767714392,0.6729992201391498,-1.4252591360334188,-4.9498308144143905,-4.965639349265447,9.575336473052682,7.731639002819358,4.471520436861803],[150.25881531101186,21.802064338814798,-44.29274109687284,-4.235352830060731,-17.666143446644888,4.9798391833912055,-1.574840791115542,-6.854201532454216,-1.8143245686618155,-4.957256272327222,-0.6412573771044269,-6.95491703313055,-4.444404538369984],[287.93352127075195,14.194788069449029,-20.8542738190565,-7.562937180414286,-14.707519757324707,-4.513873704074549,1.5940133665028693,3.2558816005724847,-15.335756189096948,-8.504015616224859,-2.413186735930223,5.6268044007364635,6.751816072450436],[115.50524796545506,-8.63073477440851,-37.638063415961064,17.05744845244351,8.81570904694053,-18.08630831742631,-16.395856407749676,3.970968806036655,-2.7254234917680984,8.004075348310908,-0.11591750872191792,-0.5005035625442792,-15.758129772662285],[268.70514822006226,11.058412748164379,-25.46773213645445,7.854306786931966,-14.017515187703342,-14.379088043050848,-21.413163420916916,2.2366286203943497,-1.0553530081388782,-2.3356768880969265,0.10030365029617716,4.147538959725798,-0.42293309969775184],[255.10408759117126,2.9839333802266212,-49.600206177094925,2.7082939644832824,-7.2004856031296836,11.059309271268924,-11.64943878164858,1.1397210888628289,0.36158961127223277,2.231319210013885,-1.730746884878434,-3.321928605224966,-8.447466919033095],[84.14148223493248,15.859740286737232,-22.195860128599918,-23.08961596591042,-11.095667542368714,-12.96894588951639,-1.4930155114211423,12.71942219098584,-1.298092031126412,9.202470233313507,1.1431892806593567,5.054566638857799,-8.850849499582313],[189.9462730884552,2.744879223638137,-7.331325644856165,57.79649490383166,-4.205954299931147,6.58638750953723,-3.205038524907011,10.063949243162675,4.582336877558352,8.01768946256971,-0.6639784855627093,-2.7570988499979228,-2.780719248660455],[87.42413486167789,-7.31100119861122,-43.71139520044253,-4.370058208548226,12.392967006543856,0.6214350981981202,1.8937882920865754,1.6551361395914503,-15.42981498552919,14.031465459019829,2.582221766902142,-7.844305545193481,-4.959824933537969],[232.46439710259438,21.47504436668677,-11.47462630886845,34.90558078823852,-5.769798908648713,22.686108124927827,8.021682382561481,12.994631329051503,-7.937309850940154,0.2743906910653294,-0.892271297543155,-3.5183034088013327,-7.8533489021890395],[78.98907087277621,22.14194057174601,-24.760027972411702,-35.92629877488124,-15.038539366261627,2.176871882838234,10.802981476125487,9.17645733690161,-7.286873817836289,0.6957427358087489,-1.7550364090184347,5.943604438208206,-3.640778614585323],[160.69393920898438,-30.095199207701558,-18.472355549389516,34.71995126326609,-27.004370853267453,9.11287265597757,7.045393126914499,3.7604267549238046,6.553858091793051,-1.1125485854343453,-6.661311261703074,3.242069965782032,-4.029772522354406],[91.09846711484715,10.76485752634354,-24.674128045202018,-19.593985768631658,-10.605193810366648,-8.245362264928461,-9.82994034803978,8.260168962477215,3.5388515978458646,11.526707826582513,5.558638820545692,4.128414292770646,-9.681738221297014],[77.88874008320272,1.2515539060692427,-20.264770688232147,-4.746776937176215,6.941418880911637,-11.34061828070165,-6.192039991198347,11.14066673721247,-6.248096482212682,-1.2284236625980625,-11.006308775083244,11.801742302534763,-8.913770555887485]]"}
--------------------------------------------------------------------------------