├── .gitignore ├── LICENSE.md ├── README.md ├── cli.js ├── docs ├── 404.html ├── assets │ ├── images │ │ ├── favicon.ico │ │ └── icons │ │ │ ├── bitbucket-670608a71a.svg │ │ │ ├── github-1da075986e.svg │ │ │ └── gitlab-5ad3f9f9e5.svg │ ├── javascripts │ │ ├── application-0b7df094bf.js │ │ └── modernizr-56ade86843.js │ └── stylesheets │ │ ├── application-b1a1975878.css │ │ └── application-f78e5cb881.palette.css ├── cli │ └── index.html ├── config │ └── index.html ├── img │ ├── favicon.ico │ ├── favicon.png │ └── pnlogo.png ├── index.html ├── install │ └── index.html ├── mkdocs │ ├── js │ │ ├── lunr.min.js │ │ ├── mustache.min.js │ │ ├── require.js │ │ ├── search-results-template.mustache │ │ ├── search.js │ │ └── text.js │ └── search_index.json ├── notes │ └── index.html ├── project │ └── index.html └── sitemap.xml ├── lib ├── build.js ├── bundle.js ├── paths.js ├── update.js ├── utils.js └── watch.js ├── package.json ├── pnconfig.json └── tpl ├── game ├── css │ └── index.css ├── favicon.ico ├── img │ ├── logo.png │ ├── pnlogo.png │ └── preload.png ├── index.html └── js │ ├── BootState.js │ ├── GameState.js │ ├── MenuState.js │ ├── PreloadState.js │ └── index.js └── pnkit.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | __phaser-node-kit__ 2 | 3 | _Phaser Node Kit (PhaserJS + NodeJS)_ 4 | 5 | © 2017 develephant 6 | 7 | The MIT License (MIT) 8 | --------------------- 9 | 10 | Copyright © 2017 develephant 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy of 13 | this software and associated documentation files (the "Software"), to deal in 14 | the Software without restriction, including without limitation the rights to 15 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 16 | the Software, and to permit persons to whom the Software is furnished to do so, 17 | subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in all 20 | copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 24 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 25 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 26 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `phaser-node-kit` 2 | 3 | ![pnkit](http://develephant.com/projects/pnlogo.png) 4 | 5 | ### Rapid Game Development with PhaserJS and Node for Modern Browsers 6 | 7 | ## Install 8 | 9 | ``` 10 | npm i -g phaser-node-kit 11 | ``` 12 | 13 | ## Insert Coin 14 | 15 | It takes only two steps to start making games with _Phaser Node Kit_: 16 | 17 | 1. Run the initialization in a folder of your choosing: `pnkit init` 18 | 19 | 2. Start the watch server and build on file updates: `pnkit watch` 20 | 21 | The "live" build of your game can be found at: http://localhost:5550. 22 | 23 | ## Docs 24 | 25 | ### [Click here to read the fine print.](https://develephant.github.io/phaser-node-kit/) 26 | 27 | #### `phaser-node-kit` ⋆ © 2017 develephant ⋆ MIT license 28 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * phaser-node-kit 5 | * @author C. Byerley 6 | * @copyright (c)2017 develephant.com 7 | * @license MIT 8 | * https://github.com/develephant/phaser-node-kit 9 | */ 10 | const pkg = require('./package') 11 | const ArgParser = require('argparse').ArgumentParser 12 | 13 | const Build = require('./lib/build') 14 | const Watch = require('./lib/watch') 15 | const Update = require('./lib/update') 16 | 17 | const builder = new Build() 18 | const watcher = new Watch() 19 | const updater = new Update() 20 | 21 | const parser = new ArgParser({ 22 | description: 'Phaser Node Kit', 23 | version: pkg.version, 24 | allowAbbrev: false, 25 | epilog: '(c)2017 develephant.com' 26 | }) 27 | 28 | parser.addArgument('action', { 29 | help: 'Phaser Node Kit Actions', 30 | choices: [ 31 | 'init', 32 | 'watch', 33 | 'sync', 34 | 'update' 35 | ] 36 | }) 37 | 38 | const args = parser.parseArgs() 39 | 40 | if (args.action === 'sync') { 41 | builder.runInitBuild(true) 42 | } else if (args.action === 'watch') { 43 | watcher.run() 44 | } else if (args.action === 'init') { 45 | builder.runInitBuild() 46 | } else if (args.action === 'update') { 47 | updater.run() 48 | } 49 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 132 |
133 | 134 |
135 | 136 | 137 |
138 |
139 | 140 | 141 |
142 |
143 |
144 | 250 |
251 |
252 |
253 | 254 | 255 | 256 |
257 |
258 | 259 |

404 - Not found

260 | 261 | 262 | 263 | 264 |
265 |
266 |
267 |
268 | 269 | 270 | 288 | 289 |
290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /docs/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/docs/assets/images/favicon.ico -------------------------------------------------------------------------------- /docs/assets/images/icons/bitbucket-670608a71a.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/images/icons/github-1da075986e.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/images/icons/gitlab-5ad3f9f9e5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/assets/javascripts/modernizr-56ade86843.js: -------------------------------------------------------------------------------- 1 | !function(e,n,t){function r(e,n){return typeof e===n}function o(){var e,n,t,o,i,s,f;for(var a in w)if(w.hasOwnProperty(a)){if(e=[],n=w[a],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Commands - Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 309 |
310 |
311 |
312 | 313 | 314 |
315 |
316 |
317 | 318 | 360 |
361 |
362 |
363 | 364 | 365 |
366 |
367 | 368 | 369 | edit 370 | 371 | 372 |

Commands

373 |

Phaser Node Kit only has a couple commands to get you up and running.

374 |

Init

375 |

pnkit init

376 |

To create a new Phaser Node Kit project do the following:

377 |
    378 |
  • 379 |

    Create a new empty directory.

    380 |
  • 381 |
  • 382 |

    Create a package.json file (optional).

    383 |
  • 384 |
  • 385 |

    Run pnkit init on the command line in the directory you created.

    386 |
  • 387 |
388 |
389 |

You can create your own package.json before running pnkit init or a bare one will be created for you.

390 |
391 |

Watch

392 |

Watch the game development files, and trigger a build on changes:

393 |

pnkit watch

394 |

Phaser Node Kit will now run a build when any of the files are updated.

395 |

View the current game state in your browser at http://127.0.0.1:5550.

396 |

You can leave the browser window running, and it will refresh with each build.

397 |

Sync

398 |

There may be times when you want to clean the build directory between builds. Or perhaps you've added some files while the watcher wasn't running to catch them. You can run pnkit sync to get your build folder to be in sync again with the game folder.

399 |

pnkit sync

400 |

This will flush the build folder and rebuild the project in its current state.

401 |

Update

402 |

Updates the PhaserJS library to its latest version.

403 |

sudo pnkit update

404 |
405 |

Make sure to use the sudo command.

406 |
407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 |
415 |
416 |
417 |
418 | 419 | 420 | 473 | 474 |
475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | -------------------------------------------------------------------------------- /docs/config/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Configuration - Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 349 |
350 |
351 |
352 | 353 | 354 |
355 |
356 |
357 | 358 | 440 |
441 |
442 |
443 | 444 | 445 |
446 |
447 | 448 | 449 | edit 450 | 451 | 452 |

Configuration

453 |

Phaser Node Kit configuration options are minimal. You can however ignore files, directories, and extensions, as well as adjust some of the watcher settings.

454 |

pnkit.json

455 |

The Phaser Node Kit configuration can be found in the pnkit.json file at the root your project directory. This file is fairly critical to the kit's operation. You should keep it with the project.

456 |

The default configuration file looks like so:

457 |
{
458 |   "ignore": [ ".DS_Store" ],
459 |   "watch": {
460 |     "port": 5550,
461 |     "host": "127.0.0.1",
462 |     "refresh": true,
463 |     "startBrowser" : true
464 |   },
465 |   "debug": true
466 | }
467 | 
468 | 469 |

Configuration Keys

470 |

ignore

471 |

You can fill this array with folders, files, and extension types that you would like the watcher to ignore.

472 |

For example:

473 |
{
474 |   "ignore": [".tps", "stuff", "secret.json"] 
475 | }
476 | 
477 | 
478 | 479 |

watch

480 |

This watch section contains settings for the watcher.

481 |

port

482 |

The port to serve the "live" game build on. The default is 5550.

483 |

host

484 |

The host to serve the "live" game build on. Change this to test the build over your local network. The default is 127.0.0.1.

485 |

refresh

486 |

Whether to refresh the browser automatically on updates to the project. If you set this to false, you will need to remember to refresh your browser to see the current build. The default is true.

487 |

startBrowser

488 |

Whether to start the browser automatically when running watch. The default is true.

489 |

debug

490 |

The debug key is a boolean value. If set to true, then the bundle will also contain inline source maps, making it easier to debug your code. If false no source maps are generated.

491 |

Make sure to set debug to false when making your final build. This makes the bundle leaner.

492 |
493 |
494 |

If you change the configuration while the watcher is running, be sure to stop and restart it to make the configuration active.

495 |
496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 |
504 |
505 |
506 |
507 | 508 | 509 | 562 | 563 |
564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/docs/img/favicon.png -------------------------------------------------------------------------------- /docs/img/pnlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/docs/img/pnlogo.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 302 |
303 |
304 |
305 | 306 | 307 |
308 |
309 |
310 | 311 | 346 |
347 |
348 |
349 | 350 | 351 |
352 |
353 | 354 | 355 | edit 356 | 357 | 358 |

Phaser Node Kit

359 |

pnkit

360 |

Rapid Game Development with PhaserJS and Node for Modern Browsers.

361 |

What Is It?

362 |

Phaser Node Kit is a build tool and project template for creating PhaserJS games using NodeJS.

363 |

You may be asking yourself, why? And that I can't answer clearly. I just spend most of my time in the Node environment.

364 |

The build tool is basically a collection of some popular libraries to get your game built for distribution using Node. The project template is a minimal running Phaser.js game, with included states.

365 |

The major components consist of:

366 |

Node

367 |

Browserify

368 |

and of course...

369 |

PhaserJS

370 |

How It Works

371 |

Phaser Node Kit only cares about two types of files, javascript and everything else.

372 |

With the javascript, the kit will bundle up your game code with Browserify on changes. For everything else, the kit "hot" copies the files in and out of the build directory. The Phaser CE library is added as a vendor file when you initialize a new game project. It all allows you to make games quicker using Node.

373 |

Some Context

374 |

I've been playing with games for nearly two and a half decades. I was an ActionScript developer from version 1 through 3, and spent the last five working with the Lua game development community. Now I'm focusing my efforts on Phaser.js.

375 |

Being able to hit the ground running when inspiration calls is crucial. I prototype constantly (or just noodle around) and don't like to spend time on tooling.

376 |

The goal for Phaser Node Kit was to be able to get to the creative phase as quick as possible.

377 |

So with a pnkit init and a pnkit watch, I'm looking at a "live" build in my browser ready to hack on, with a build folder ready to serve or bundle with something like Cordova.

378 |

I hope it helps you to be more creative in your game development adventures as well.

379 |

^_^ Happy game making!

380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 |
388 |
389 |
390 |
391 | 392 | 393 | 432 | 433 |
434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | -------------------------------------------------------------------------------- /docs/install/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Installation - Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 295 |
296 |
297 |
298 | 299 | 300 |
301 |
302 |
303 | 304 | 332 |
333 |
334 |
335 | 336 | 337 |
338 |
339 | 340 | 341 | edit 342 | 343 | 344 |

Installation

345 |

Phaser Node Kit is a Node application that is installed globally, making the tool at the ready for when creative game sparks fly.

346 |

You can have a running "live" game development framework up in a handful of seconds.

347 |

Requirements

348 |

To run Phaser Node Kit you will need NodeJS version 6 or higher.

349 |

npm

350 |

Using npm, run the following on the command line:

351 |

sudo npm i -g phaser-node-kit

352 |

This will install the tool, and make it available anywhere on your system as pnkit.

353 |

You can get the latest version information to be certain it's installed:

354 |

pnkit -v

355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 |
363 |
364 |
365 |
366 | 367 | 368 | 421 | 422 |
423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | -------------------------------------------------------------------------------- /docs/mkdocs/js/lunr.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.0 3 | * Copyright (C) 2016 Oliver Nightingale 4 | * MIT Licensed 5 | * @license 6 | */ 7 | !function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.7.0",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.tokenizer.load=function(t){var e=this.registeredFunctions[t];if(!e)throw new Error("Cannot load un-registered function: "+t);return e},t.tokenizer.label="default",t.tokenizer.registeredFunctions={"default":t.tokenizer},t.tokenizer.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing tokenizer: "+n),e.label=n,this.registeredFunctions[n]=e},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone();for(var r=0,o=n.toArray();rp;p++)c[p]===a&&d++;h+=d/f*l.boost}}this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(this.tokenizerFn(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),d=Object.keys(f),p=d.length,v=0;p>v;v++)l.add(f[d[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,tokenizer:this.tokenizerFn.label,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(u),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),k=new RegExp("^"+r+i+"[^aeiouwxy]$"),x=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,F=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,_=/^(.+?)(s|t)(ion)$/,z=/^(.+?)e$/,O=/ll$/,P=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=p,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=g,a=m,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,u=k,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=x,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=F,a=_,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=z,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=P,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=O,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n":">",'"':""","'":"'","/":"/"};function escapeHtml(string){return String(string).replace(/[&<>"'\/]/g,function(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tags){if(typeof tags==="string")tags=tags.split(spaceRe,2);if(!isArray(tags)||tags.length!==2)throw new Error("Invalid tags: "+tags);openingTagRe=new RegExp(escapeRegExp(tags[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tags[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tags[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function(){return this.tail===""};Scanner.prototype.scan=function(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function(view){return new Context(view,this)};Context.prototype.lookup=function(name){var cache=this.cache;var value;if(name in cache){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index")value=this._renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this._unescapedValue(token,context);else if(symbol==="name")value=this._escapedValue(token,context);else if(symbol==="text")value=this._rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype._renderSection=function(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;jthis.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&& 19 | (f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a= 20 | this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f); 21 | if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval", 22 | "fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b, 23 | a);this.check()}));this.errback?q(a,"error",u(this,this.errback)):this.events.error&&q(a,"error",u(this,function(a){this.emit("error",a)}))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b, 24 | registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a); 25 | b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n, 26 | q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d, 27 | e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==e&&(!("."===k||".."===k)||1e.attachEvent.toString().indexOf("[native code"))&& 34 | !Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"), 35 | s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"=== 36 | b.readyState)return N=b}),e=N;e&&(b||(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this); 37 | -------------------------------------------------------------------------------- /docs/mkdocs/js/search-results-template.mustache: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /docs/mkdocs/js/search.js: -------------------------------------------------------------------------------- 1 | require([ 2 | base_url + '/mkdocs/js/mustache.min.js', 3 | base_url + '/mkdocs/js/lunr.min.js', 4 | 'text!search-results-template.mustache', 5 | 'text!../search_index.json', 6 | ], function (Mustache, lunr, results_template, data) { 7 | "use strict"; 8 | 9 | function getSearchTerm() 10 | { 11 | var sPageURL = window.location.search.substring(1); 12 | var sURLVariables = sPageURL.split('&'); 13 | for (var i = 0; i < sURLVariables.length; i++) 14 | { 15 | var sParameterName = sURLVariables[i].split('='); 16 | if (sParameterName[0] == 'q') 17 | { 18 | return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20')); 19 | } 20 | } 21 | } 22 | 23 | var index = lunr(function () { 24 | this.field('title', {boost: 10}); 25 | this.field('text'); 26 | this.ref('location'); 27 | }); 28 | 29 | data = JSON.parse(data); 30 | var documents = {}; 31 | 32 | for (var i=0; i < data.docs.length; i++){ 33 | var doc = data.docs[i]; 34 | doc.location = base_url + doc.location; 35 | index.add(doc); 36 | documents[doc.location] = doc; 37 | } 38 | 39 | var search = function(){ 40 | 41 | var query = document.getElementById('mkdocs-search-query').value; 42 | var search_results = document.getElementById("mkdocs-search-results"); 43 | while (search_results.firstChild) { 44 | search_results.removeChild(search_results.firstChild); 45 | } 46 | 47 | if(query === ''){ 48 | return; 49 | } 50 | 51 | var results = index.search(query); 52 | 53 | if (results.length > 0){ 54 | for (var i=0; i < results.length; i++){ 55 | var result = results[i]; 56 | doc = documents[result.ref]; 57 | doc.base_url = base_url; 58 | doc.summary = doc.text.substring(0, 200); 59 | var html = Mustache.to_html(results_template, doc); 60 | search_results.insertAdjacentHTML('beforeend', html); 61 | } 62 | } else { 63 | search_results.insertAdjacentHTML('beforeend', "

No results found

"); 64 | } 65 | 66 | if(jQuery){ 67 | /* 68 | * We currently only automatically hide bootstrap models. This 69 | * requires jQuery to work. 70 | */ 71 | jQuery('#mkdocs_search_modal a').click(function(){ 72 | jQuery('#mkdocs_search_modal').modal('hide'); 73 | }); 74 | } 75 | 76 | }; 77 | 78 | var search_input = document.getElementById('mkdocs-search-query'); 79 | 80 | var term = getSearchTerm(); 81 | if (term){ 82 | search_input.value = term; 83 | search(); 84 | } 85 | 86 | search_input.addEventListener("keyup", search); 87 | 88 | }); 89 | -------------------------------------------------------------------------------- /docs/mkdocs/js/text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. 3 | * Available via the MIT or new BSD license. 4 | * see: http://github.com/requirejs/text for details 5 | */ 6 | /*jslint regexp: true */ 7 | /*global require, XMLHttpRequest, ActiveXObject, 8 | define, window, process, Packages, 9 | java, location, Components, FileUtils */ 10 | 11 | define(['module'], function (module) { 12 | 'use strict'; 13 | 14 | var text, fs, Cc, Ci, xpcIsWindows, 15 | progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], 16 | xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, 17 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, 18 | hasLocation = typeof location !== 'undefined' && location.href, 19 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), 20 | defaultHostName = hasLocation && location.hostname, 21 | defaultPort = hasLocation && (location.port || undefined), 22 | buildMap = {}, 23 | masterConfig = (module.config && module.config()) || {}; 24 | 25 | text = { 26 | version: '2.0.12', 27 | 28 | strip: function (content) { 29 | //Strips declarations so that external SVG and XML 30 | //documents can be added to a document without worry. Also, if the string 31 | //is an HTML document, only the part inside the body tag is returned. 32 | if (content) { 33 | content = content.replace(xmlRegExp, ""); 34 | var matches = content.match(bodyRegExp); 35 | if (matches) { 36 | content = matches[1]; 37 | } 38 | } else { 39 | content = ""; 40 | } 41 | return content; 42 | }, 43 | 44 | jsEscape: function (content) { 45 | return content.replace(/(['\\])/g, '\\$1') 46 | .replace(/[\f]/g, "\\f") 47 | .replace(/[\b]/g, "\\b") 48 | .replace(/[\n]/g, "\\n") 49 | .replace(/[\t]/g, "\\t") 50 | .replace(/[\r]/g, "\\r") 51 | .replace(/[\u2028]/g, "\\u2028") 52 | .replace(/[\u2029]/g, "\\u2029"); 53 | }, 54 | 55 | createXhr: masterConfig.createXhr || function () { 56 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first. 57 | var xhr, i, progId; 58 | if (typeof XMLHttpRequest !== "undefined") { 59 | return new XMLHttpRequest(); 60 | } else if (typeof ActiveXObject !== "undefined") { 61 | for (i = 0; i < 3; i += 1) { 62 | progId = progIds[i]; 63 | try { 64 | xhr = new ActiveXObject(progId); 65 | } catch (e) {} 66 | 67 | if (xhr) { 68 | progIds = [progId]; // so faster next time 69 | break; 70 | } 71 | } 72 | } 73 | 74 | return xhr; 75 | }, 76 | 77 | /** 78 | * Parses a resource name into its component parts. Resource names 79 | * look like: module/name.ext!strip, where the !strip part is 80 | * optional. 81 | * @param {String} name the resource name 82 | * @returns {Object} with properties "moduleName", "ext" and "strip" 83 | * where strip is a boolean. 84 | */ 85 | parseName: function (name) { 86 | var modName, ext, temp, 87 | strip = false, 88 | index = name.indexOf("."), 89 | isRelative = name.indexOf('./') === 0 || 90 | name.indexOf('../') === 0; 91 | 92 | if (index !== -1 && (!isRelative || index > 1)) { 93 | modName = name.substring(0, index); 94 | ext = name.substring(index + 1, name.length); 95 | } else { 96 | modName = name; 97 | } 98 | 99 | temp = ext || modName; 100 | index = temp.indexOf("!"); 101 | if (index !== -1) { 102 | //Pull off the strip arg. 103 | strip = temp.substring(index + 1) === "strip"; 104 | temp = temp.substring(0, index); 105 | if (ext) { 106 | ext = temp; 107 | } else { 108 | modName = temp; 109 | } 110 | } 111 | 112 | return { 113 | moduleName: modName, 114 | ext: ext, 115 | strip: strip 116 | }; 117 | }, 118 | 119 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, 120 | 121 | /** 122 | * Is an URL on another domain. Only works for browser use, returns 123 | * false in non-browser environments. Only used to know if an 124 | * optimized .js version of a text resource should be loaded 125 | * instead. 126 | * @param {String} url 127 | * @returns Boolean 128 | */ 129 | useXhr: function (url, protocol, hostname, port) { 130 | var uProtocol, uHostName, uPort, 131 | match = text.xdRegExp.exec(url); 132 | if (!match) { 133 | return true; 134 | } 135 | uProtocol = match[2]; 136 | uHostName = match[3]; 137 | 138 | uHostName = uHostName.split(':'); 139 | uPort = uHostName[1]; 140 | uHostName = uHostName[0]; 141 | 142 | return (!uProtocol || uProtocol === protocol) && 143 | (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && 144 | ((!uPort && !uHostName) || uPort === port); 145 | }, 146 | 147 | finishLoad: function (name, strip, content, onLoad) { 148 | content = strip ? text.strip(content) : content; 149 | if (masterConfig.isBuild) { 150 | buildMap[name] = content; 151 | } 152 | onLoad(content); 153 | }, 154 | 155 | load: function (name, req, onLoad, config) { 156 | //Name has format: some.module.filext!strip 157 | //The strip part is optional. 158 | //if strip is present, then that means only get the string contents 159 | //inside a body tag in an HTML string. For XML/SVG content it means 160 | //removing the declarations so the content can be inserted 161 | //into the current doc without problems. 162 | 163 | // Do not bother with the work if a build and text will 164 | // not be inlined. 165 | if (config && config.isBuild && !config.inlineText) { 166 | onLoad(); 167 | return; 168 | } 169 | 170 | masterConfig.isBuild = config && config.isBuild; 171 | 172 | var parsed = text.parseName(name), 173 | nonStripName = parsed.moduleName + 174 | (parsed.ext ? '.' + parsed.ext : ''), 175 | url = req.toUrl(nonStripName), 176 | useXhr = (masterConfig.useXhr) || 177 | text.useXhr; 178 | 179 | // Do not load if it is an empty: url 180 | if (url.indexOf('empty:') === 0) { 181 | onLoad(); 182 | return; 183 | } 184 | 185 | //Load the text. Use XHR if possible and in a browser. 186 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { 187 | text.get(url, function (content) { 188 | text.finishLoad(name, parsed.strip, content, onLoad); 189 | }, function (err) { 190 | if (onLoad.error) { 191 | onLoad.error(err); 192 | } 193 | }); 194 | } else { 195 | //Need to fetch the resource across domains. Assume 196 | //the resource has been optimized into a JS module. Fetch 197 | //by the module name + extension, but do not include the 198 | //!strip part to avoid file system issues. 199 | req([nonStripName], function (content) { 200 | text.finishLoad(parsed.moduleName + '.' + parsed.ext, 201 | parsed.strip, content, onLoad); 202 | }); 203 | } 204 | }, 205 | 206 | write: function (pluginName, moduleName, write, config) { 207 | if (buildMap.hasOwnProperty(moduleName)) { 208 | var content = text.jsEscape(buildMap[moduleName]); 209 | write.asModule(pluginName + "!" + moduleName, 210 | "define(function () { return '" + 211 | content + 212 | "';});\n"); 213 | } 214 | }, 215 | 216 | writeFile: function (pluginName, moduleName, req, write, config) { 217 | var parsed = text.parseName(moduleName), 218 | extPart = parsed.ext ? '.' + parsed.ext : '', 219 | nonStripName = parsed.moduleName + extPart, 220 | //Use a '.js' file name so that it indicates it is a 221 | //script that can be loaded across domains. 222 | fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; 223 | 224 | //Leverage own load() method to load plugin value, but only 225 | //write out values that do not have the strip argument, 226 | //to avoid any potential issues with ! in file names. 227 | text.load(nonStripName, req, function (value) { 228 | //Use own write() method to construct full module value. 229 | //But need to create shell that translates writeFile's 230 | //write() to the right interface. 231 | var textWrite = function (contents) { 232 | return write(fileName, contents); 233 | }; 234 | textWrite.asModule = function (moduleName, contents) { 235 | return write.asModule(moduleName, fileName, contents); 236 | }; 237 | 238 | text.write(pluginName, nonStripName, textWrite, config); 239 | }, config); 240 | } 241 | }; 242 | 243 | if (masterConfig.env === 'node' || (!masterConfig.env && 244 | typeof process !== "undefined" && 245 | process.versions && 246 | !!process.versions.node && 247 | !process.versions['node-webkit'])) { 248 | //Using special require.nodeRequire, something added by r.js. 249 | fs = require.nodeRequire('fs'); 250 | 251 | text.get = function (url, callback, errback) { 252 | try { 253 | var file = fs.readFileSync(url, 'utf8'); 254 | //Remove BOM (Byte Mark Order) from utf8 files if it is there. 255 | if (file.indexOf('\uFEFF') === 0) { 256 | file = file.substring(1); 257 | } 258 | callback(file); 259 | } catch (e) { 260 | if (errback) { 261 | errback(e); 262 | } 263 | } 264 | }; 265 | } else if (masterConfig.env === 'xhr' || (!masterConfig.env && 266 | text.createXhr())) { 267 | text.get = function (url, callback, errback, headers) { 268 | var xhr = text.createXhr(), header; 269 | xhr.open('GET', url, true); 270 | 271 | //Allow plugins direct access to xhr headers 272 | if (headers) { 273 | for (header in headers) { 274 | if (headers.hasOwnProperty(header)) { 275 | xhr.setRequestHeader(header.toLowerCase(), headers[header]); 276 | } 277 | } 278 | } 279 | 280 | //Allow overrides specified in config 281 | if (masterConfig.onXhr) { 282 | masterConfig.onXhr(xhr, url); 283 | } 284 | 285 | xhr.onreadystatechange = function (evt) { 286 | var status, err; 287 | //Do not explicitly handle errors, those should be 288 | //visible via console output in the browser. 289 | if (xhr.readyState === 4) { 290 | status = xhr.status || 0; 291 | if (status > 399 && status < 600) { 292 | //An http 4xx or 5xx error. Signal an error. 293 | err = new Error(url + ' HTTP status: ' + status); 294 | err.xhr = xhr; 295 | if (errback) { 296 | errback(err); 297 | } 298 | } else { 299 | callback(xhr.responseText); 300 | } 301 | 302 | if (masterConfig.onXhrComplete) { 303 | masterConfig.onXhrComplete(xhr, url); 304 | } 305 | } 306 | }; 307 | xhr.send(null); 308 | }; 309 | } else if (masterConfig.env === 'rhino' || (!masterConfig.env && 310 | typeof Packages !== 'undefined' && typeof java !== 'undefined')) { 311 | //Why Java, why is this so awkward? 312 | text.get = function (url, callback) { 313 | var stringBuffer, line, 314 | encoding = "utf-8", 315 | file = new java.io.File(url), 316 | lineSeparator = java.lang.System.getProperty("line.separator"), 317 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), 318 | content = ''; 319 | try { 320 | stringBuffer = new java.lang.StringBuffer(); 321 | line = input.readLine(); 322 | 323 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 324 | // http://www.unicode.org/faq/utf_bom.html 325 | 326 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: 327 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 328 | if (line && line.length() && line.charAt(0) === 0xfeff) { 329 | // Eat the BOM, since we've already found the encoding on this file, 330 | // and we plan to concatenating this buffer with others; the BOM should 331 | // only appear at the top of a file. 332 | line = line.substring(1); 333 | } 334 | 335 | if (line !== null) { 336 | stringBuffer.append(line); 337 | } 338 | 339 | while ((line = input.readLine()) !== null) { 340 | stringBuffer.append(lineSeparator); 341 | stringBuffer.append(line); 342 | } 343 | //Make sure we return a JavaScript string and not a Java string. 344 | content = String(stringBuffer.toString()); //String 345 | } finally { 346 | input.close(); 347 | } 348 | callback(content); 349 | }; 350 | } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && 351 | typeof Components !== 'undefined' && Components.classes && 352 | Components.interfaces)) { 353 | //Avert your gaze! 354 | Cc = Components.classes; 355 | Ci = Components.interfaces; 356 | Components.utils['import']('resource://gre/modules/FileUtils.jsm'); 357 | xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); 358 | 359 | text.get = function (url, callback) { 360 | var inStream, convertStream, fileObj, 361 | readData = {}; 362 | 363 | if (xpcIsWindows) { 364 | url = url.replace(/\//g, '\\'); 365 | } 366 | 367 | fileObj = new FileUtils.File(url); 368 | 369 | //XPCOM, you so crazy 370 | try { 371 | inStream = Cc['@mozilla.org/network/file-input-stream;1'] 372 | .createInstance(Ci.nsIFileInputStream); 373 | inStream.init(fileObj, 1, 0, false); 374 | 375 | convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] 376 | .createInstance(Ci.nsIConverterInputStream); 377 | convertStream.init(inStream, "utf-8", inStream.available(), 378 | Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); 379 | 380 | convertStream.readString(inStream.available(), readData); 381 | convertStream.close(); 382 | inStream.close(); 383 | callback(readData.value); 384 | } catch (e) { 385 | throw new Error((fileObj && fileObj.path || '') + ': ' + e); 386 | } 387 | }; 388 | } 389 | return text; 390 | }); 391 | -------------------------------------------------------------------------------- /docs/notes/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Notes - Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 295 |
296 |
297 |
298 | 299 | 300 |
301 |
302 |
303 | 304 | 332 |
333 |
334 |
335 | 336 | 337 |
338 |
339 | 340 | 341 | edit 342 | 343 | 344 |

Notes

345 |

Phaser.js Versions

346 |

When you first install Phaser Node Kit the current release of Phaser CE is downloaded for use in any new projects. This version will remain until the kit is updated.

347 |

If you would like to use a different version of Phaser.js simply place a phaser.min.js file of your choosing in the game/vendor directory. Files in the game directory are never overwritten by the watcher.

348 |

See the update command as well.

349 |

Misc

350 |

Purple whales are cute.

351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 |
359 |
360 |
361 |
362 | 363 | 364 | 403 | 404 |
405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | -------------------------------------------------------------------------------- /docs/project/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Project Template - Phaser Node Kit 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 134 |
135 | 136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 |
146 | 391 |
392 |
393 |
394 | 395 | 396 |
397 |
398 |
399 | 400 | 524 |
525 |
526 |
527 | 528 | 529 |
530 |
531 | 532 | 533 | edit 534 | 535 | 536 |

Project Template

537 |

Phaser Node Kit comes with a very basic game project template to get you started. It contains some basic states, and other boilerplate. Consider it your "blank" canvas.

538 |

New Projects

539 |

To create a new Phaser Node Kit project do the following:

540 |
    541 |
  • Create a new empty directory.
  • 542 |
  • Create a package.json file (optional).
  • 543 |
  • Run pnkit init on the command line in the empty directory.
  • 544 |
545 |

Let's take look at the innards, and how to use it effectively.

546 |

The Project Tree

547 |

Here you can see an overview of the default project. Everything is contained in the game directory:

548 |
game
549 | ├── css
550 | │   └── index.css
551 | ├── favicon.ico
552 | ├── img
553 | │   ├── logo.png
554 | │   ├── pnlogo.png
555 | │   └── preload.png
556 | ├── index.html
557 | ├── js
558 | │   ├── BootState.js
559 | │   ├── GameState.js
560 | │   ├── MenuState.js
561 | │   ├── PreloadState.js
562 | │   └── index.js
563 | └── vendor
564 |     └── phaser.min.js
565 | 
566 | 567 |
568 |

There is of course the build directory at the project root, but we pretend that doesn't exist except for viewing and distributing. Never manually place files in the build directory, they risk being overwritten at any time.

569 |
570 |

Directories and Files

571 |

While the watcher is running (pnkit watch) simply place or create a new directory or file in the game folder to add it to the project. Remove a directory to remove it from the project.

572 |

Some additional folders you may want could be: fonts, data, snds, etc.

573 |

Any items (besides javascript files) that are added will be "hot" copied to the build directory. The reverse holds true when removing items.

574 |
575 |

If you add items to the game directory while the watcher is not active, you will need to "sync" the project (pnkit sync).

576 |
577 |

See Commands.

578 |

Javascript

579 |

The js directory is a special folder. It must reside in the game folder, and be named exactly js.

580 |

All of your .js files and classes will live in this directory. When javascript files in this directory are updated, the bundler will run a pass on the files, creating a Browserify bundle.

581 |
582 |

Javascript files are only compiled if they live in the game/js directory. Any other file type is added (or removed) from the build folder as-is.

583 |
584 |

Indexes

585 |

The index.html, index.js, and index.css all contain basic boilerplate for their particular domain.

586 |

index.html

587 |
<!DOCTYPE html>
588 |   <head>
589 |     <meta charset="utf-8">
590 |     <meta name="viewport" content="user-scalable=no, initial-scale=1">
591 | 
592 |     <title>Phaser Node Kit</title>
593 | 
594 |     <link rel="stylesheet" type="text/css" href="css/index.css">
595 | 
596 |     <script src="./vendor/phaser.min.js"></script>
597 |     <script src="./bundle.js"></script>
598 | 
599 |   </head>
600 |   <body><div div="game"></div></body>
601 | </html>
602 | 
603 | 604 |

Here phaser.js is loaded separately to keep compile times quick. It needs no additional compilation as it is. The bundle.js is your game code bundled up with Browserify.

605 |

index.js

606 |
Phaser.Device.whenReady(() => {
607 |   const bootState     = require('./BootState')
608 |   const preloadState  = require('./PreloadState')
609 |   const menuState     = require('./MenuState')
610 |   const gameState     = require('./GameState')
611 | 
612 |   const game = new Phaser.Game(800, 600, Phaser.AUTO, 'game')
613 | 
614 |   game.stage.backgroundColor = 0x000000
615 | 
616 |   game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL
617 |   game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL
618 | 
619 |   game.scale.setMinMax(800, 600)
620 | 
621 |   game.scale.pageAlignVertically = true
622 |   game.scale.pageAlignHorizontally = true
623 | 
624 |   game.state.add('Boot',      bootState)
625 |   game.state.add('Preload',   preloadState)
626 |   game.state.add('MainMenu',  menuState)
627 |   game.state.add('Game',      gameState)
628 | 
629 |   game.state.start('Boot')
630 | })
631 | 
632 | 633 |

The js/index.js file contains state assignments, the initial game object creation, and configuration code. It then launches into the Boot state. If you have needs for additional states, this is where they are assigned.

634 |

Here is where you also make adjustments to the initial game object configuration as well.

635 |

In particular, the index.js contains:

636 |
    637 |
  • Background color
  • 638 |
  • Scale mode
  • 639 |
  • Fullscreen mode
  • 640 |
  • Scale min/max
  • 641 |
  • Container alignment
  • 642 |
643 |

If you like your backgrounds black, and develop in an 800x600 display size, you generally don't need to touch this file.

644 |

index.css

645 |

The index.css simply contains an implementation of "clean.css" for better visual compatibilty across devices. It also contains a global background color.

646 |

States

647 |

BootState

648 |

js/BootState.js

649 |

The BootState is the first state that is run once Phaser is ready for it. Here we preload the "loading" bar into the image cache, and also set the maxPointers property.

650 |
class BootState {
651 | 
652 |   preload() {
653 |     this.load.image('preload', 'img/preload.png')
654 |   }
655 | 
656 |   create() {
657 |     this.input.maxPointers = 1
658 |     this.state.start('Preload')
659 |   }
660 | 
661 |   update() { }
662 |   render() { }
663 | }
664 | 
665 | module.exports = BootState
666 | 
667 | 668 |

Once the BootState is done, it will automatically launch into the next state, which is the...

669 |

PreloadState

670 |

js/PreloadState.js

671 |

In the PreloadState we load all of the assets needed for the game. While this is happening the "loading" bar will display the progress (I love free progress bars).

672 |
class PreloadState {
673 | 
674 |   preload() {
675 |     this.preloadBar = this.game.add.sprite(
676 |       this.world.centerX, 
677 |       this.world.centerY, 
678 |       'preload')
679 | 
680 |     this.preloadBar.anchor.set(.5)
681 | 
682 |     this.load.setPreloadSprite(this.preloadBar)
683 | 
684 |     this.load.image('logo', 'img/logo.png')
685 |     this.load.image('pnlogo', 'img/pnlogo.png')
686 |   }
687 | 
688 |   create() {
689 |     this.state.start('MainMenu')
690 |   }
691 | 
692 |   update() { }
693 |   render() { }
694 | }
695 | 
696 | module.exports = PreloadState
697 | 
698 | 699 |

As far as states are concerned, you may visit this one most often to add additional assets to your game.

700 |

Once the PreloadState has run its course, it will load the MenuState.

701 | 702 |

js/MenuState.js

703 |

Main menus are generally not very complex. A background and a couple buttons is usually the bulk of it. The MenuState here is very minimal. We are simply displaying the Phaser logo, and waiting for the onTap signal from the input manager.

704 |
class MenuState {
705 | 
706 |   preload() { }
707 | 
708 |   create() {
709 |     let logo = this.add.image(
710 |       this.world.centerX, 
711 |       this.world.centerY, 
712 |       'logo')
713 | 
714 |     logo.anchor.set(.5)
715 | 
716 |     this.input.onTap.addOnce((pointer) => {
717 |       this.state.start('Game')
718 |     })
719 |   }
720 | 
721 |   update() { }
722 |   render() { }
723 | }
724 | 
725 | module.exports = MenuState
726 | 
727 | 728 |

Do what you will to it, but make sure to point to the GameState as your final destination.

729 |

GameState

730 |

js/GameState.js

731 |

Ahh, finally. Now we play. The GameState is just what it sounds like. Here is where your game takes flight.

732 |
class GameState {
733 | 
734 |   preload() { }
735 | 
736 |   create() {
737 |     let pnlogo = this.add.image(
738 |       this.world.centerX, 
739 |       this.world.centerY, 
740 |       'pnlogo')
741 | 
742 |     pnlogo.anchor.set(.5)
743 |   }
744 | 
745 |   update() { }
746 |   render() { }
747 | }
748 | 
749 | module.exports = GameState
750 | 
751 | 752 |

The game at this point is just an image (because purple whales are cute).

753 |

Creating Your Game

754 |

Ready to get your game on? Check out Phaser.io for all the goodies.

755 |

Here are a couple of other handy links as well:

756 |

Phaser CE Documentation (code)

757 |

Phaser Examples (visual)

758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 |
766 |
767 |
768 |
769 | 770 | 771 | 824 | 825 |
826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | / 7 | 2017-04-30 8 | daily 9 | 10 | 11 | 12 | 13 | 14 | /install/ 15 | 2017-04-30 16 | daily 17 | 18 | 19 | 20 | 21 | 22 | /cli/ 23 | 2017-04-30 24 | daily 25 | 26 | 27 | 28 | 29 | 30 | /config/ 31 | 2017-04-30 32 | daily 33 | 34 | 35 | 36 | 37 | 38 | /project/ 39 | 2017-04-30 40 | daily 41 | 42 | 43 | 44 | 45 | 46 | /notes/ 47 | 2017-04-30 48 | daily 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /lib/build.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | const { pp } = require('./utils') 9 | const fs = require('fs-extra') 10 | const get = require('simple-get') 11 | const path = require('path') 12 | const paths = require('./paths') 13 | const spawn = require('child_process').spawnSync 14 | 15 | const Bundle = require('./bundle') 16 | 17 | class Build { 18 | constructor() { 19 | this.bundler = new Bundle() 20 | this.pnconfig = require(paths.cli.config) 21 | this.kitconf = null 22 | this.shouldRefresh = true 23 | } 24 | 25 | refreshPage() { 26 | if (this.shouldRefresh) { 27 | let watchPort = this.kitconf.watch.port || this.pnconfig.watch.port 28 | let watchHost = this.kitconf.watch.host || this.pnconfig.watch.host 29 | 30 | get(`http://${watchHost}:${watchPort}/__lightserver__/trigger`, (err, resp) => { 31 | if (err) { 32 | pp.err(err) 33 | } 34 | }) 35 | } 36 | } 37 | 38 | //render bare package.json 39 | initBarePackage() { 40 | fs.access(path.join(paths.base, 'package.json'), fs.constants.F_OK, (err) => { 41 | if (err && (err.code === 'ENOENT')) { 42 | const npm = spawn('npm', ['init', '-y'], { cwd: paths.base, stdio: null }) 43 | } 44 | }) 45 | } 46 | 47 | //run by the init script to set up 48 | //the initial kit scaffolding 49 | //we can do this sync'd 50 | //isClean = true for a clean (non-init) build 51 | runInitBuild(isSync) { 52 | try { 53 | //ensure a build dir 54 | fs.ensureDirSync(paths.build) 55 | 56 | //check for clean build 57 | if (isSync) { 58 | pp.log('Syncing Build') 59 | //clear build dir 60 | fs.emptyDirSync(paths.build) 61 | } else { 62 | pp.info('Initializing The Kit') 63 | this.initBarePackage() 64 | //copy tpl config 65 | fs.copySync(path.join(paths.cli.tpl, 'pnkit.json'), path.join(paths.base, 'pnkit.json')) 66 | //copy game tpl to project dir 67 | fs.copySync(paths.cli.game, paths.game) 68 | //copy phaser-ce js 69 | pp.log('Adding Phaser.js') 70 | fs.copySync(path.join(paths.cli.phaser, 'phaser.min.js'), path.join(paths.game_vendor, 'phaser.min.js')) 71 | } 72 | 73 | //copy game to build 74 | fs.copySync(paths.game, paths.build) 75 | 76 | //run first bundle 77 | this.bundler.run().then(() => { 78 | if (isSync) { 79 | let d = new Date() 80 | pp.ok(`Build Ready @${d.toLocaleTimeString()}`) 81 | } else { 82 | pp.title() 83 | pp.dashes(65) 84 | pp.info('To get started type "pnkit watch" and start building your game!') 85 | pp.log(`View a live build in your browser at: http://127.0.0.1:5550`) 86 | pp.dashes(65) 87 | } 88 | }) 89 | .catch((err) => { 90 | pp.err(err) 91 | }) 92 | } 93 | catch(err) { 94 | pp.err(err) 95 | } 96 | } 97 | 98 | //live build, bundles js directory 99 | //@refresh flag to supress page refresh 100 | run(refresh=true) { 101 | this.kitconf = require(paths.config) 102 | this.shouldRefresh = this.kitconf.watch.refresh 103 | 104 | this.bundler.run().then(() => { 105 | let d = new Date() 106 | pp.ok(`Build Ready @${d.toLocaleTimeString()}`) 107 | if (refresh) { 108 | this.refreshPage() 109 | } 110 | }) 111 | .catch((err) => { 112 | pp.err(err) 113 | }) 114 | } 115 | } 116 | 117 | module.exports = Build 118 | -------------------------------------------------------------------------------- /lib/bundle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | const { pp } = require('./utils') 9 | const browserify = require('browserify') 10 | const fs = require('fs-extra') 11 | const path = require('path') 12 | const paths = require('./paths') 13 | const spawn = require('child_process').spawn 14 | 15 | const gameJs = path.join(paths.game, 'js') 16 | const buildJs = path.join(paths.build, 'js') 17 | 18 | class Bundle { 19 | constructor() { } 20 | 21 | configureBuildTmpJs() { 22 | return new Promise((function(resolve, reject) { 23 | fs.copy(gameJs, buildJs, (err) => { 24 | if (err) { 25 | reject(err) 26 | } else { 27 | resolve() 28 | } 29 | }) 30 | })) 31 | } 32 | 33 | processBrowserify() { 34 | pp.info('Running Bundler') 35 | const config = require(paths.config) 36 | const debug = config.debug || false 37 | return new Promise(function(resolve, reject) { 38 | let ws = fs.createWriteStream(path.join(paths.build, 'bundle.js')) 39 | let b = browserify(path.join(buildJs, 'index.js'), {debug: debug}) 40 | .bundle() 41 | .pipe(ws) 42 | 43 | ws.on('error', (err) => { 44 | reject(err) 45 | }) 46 | 47 | ws.on('finish', () => { 48 | fs.remove(buildJs, (err) => { 49 | if (err) { 50 | reject(err) 51 | } else { 52 | resolve() 53 | } 54 | }) 55 | }) 56 | }) 57 | } 58 | 59 | run() { 60 | return this.configureBuildTmpJs() 61 | .then(() => { 62 | return this.processBrowserify() 63 | }) 64 | .catch((err) => { 65 | pp.err(err) 66 | }) 67 | } 68 | 69 | } 70 | 71 | module.exports = Bundle 72 | -------------------------------------------------------------------------------- /lib/paths.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | const path = require('path') 9 | 10 | const clibase = path.resolve(__dirname, '..') 11 | const libbase = path.join(clibase, 'lib') 12 | const appbase = process.cwd() 13 | 14 | module.exports = { 15 | base: appbase, 16 | game: path.join(appbase, 'game'), 17 | build: path.join(appbase, 'build'), 18 | config: path.join(appbase, 'pnkit.json'), 19 | dist: path.join(appbase, 'dist'), 20 | build_vendor: path.join(appbase, 'build', 'vendor'), 21 | game_vendor: path.join(appbase, 'game', 'vendor'), 22 | cli: { 23 | base: clibase, 24 | config: path.join(clibase, 'pnconfig.json'), 25 | game: path.join(clibase, 'tpl', 'game'), 26 | phaser: path.join(clibase, 'node_modules', 'phaser-ce', 'build'), 27 | tpl: path.join(clibase, 'tpl') 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/update.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | 9 | //Updates PhaserCE to latest 10 | 11 | const {pp} = require('./utils') 12 | const fs = require('fs-extra') 13 | const spawn = require('child_process').spawn 14 | const path = require('path') 15 | const paths = require('./paths') 16 | 17 | class Update { 18 | constructor() { } 19 | 20 | run() { 21 | pp.info('Updating PhaserJS...') 22 | const npm = spawn('npm', ['install', 'phaser-ce@latest'], { cwd: paths.cli.base, stdio: ['pipe', 'ignore', 'ignore']}) 23 | 24 | npm.on('close', (e) => { 25 | if (e === 0) { 26 | fs.copySync(path.join(paths.cli.phaser, 'phaser.min.js'), path.join(paths.game_vendor, 'phaser.min.js')) 27 | pp.ok('PhaserJS Updated!') 28 | } else if (e === 243) { 29 | pp.err('Please use "sudo pnkit update"') 30 | } else { 31 | pp.err(`An error occurred during the update: code ${e}`) 32 | } 33 | }) 34 | } 35 | } 36 | 37 | module.exports = Update 38 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | const path = require('path') 9 | 10 | //colors 11 | const clr = require('colors/safe') 12 | 13 | clr.setTheme({ 14 | ok: ['bold', 'green'], 15 | log: 'cyan', 16 | info: ['bold', 'blue'], 17 | warn: ['bold', 'yellow'], 18 | err: ['bold', 'red'], 19 | title: ['bold', 'red', 'bgBlack'], 20 | fun: 'rainbow' 21 | }) 22 | 23 | //styling 24 | function dashes(amt=80) { 25 | console.log(clr.dim('-'.repeat(amt))) 26 | } 27 | 28 | //colors direct 29 | module.exports.clr = clr 30 | 31 | //pretty print 32 | module.exports.pp = { 33 | ok: function(str) { 34 | console.log(clr.ok(`\xBB ${str}`)) 35 | }, 36 | info: function(str) { 37 | console.log(clr.info(`\xBB ${str}`)) 38 | }, 39 | warn: function(str) { 40 | console.log(clr.warn(`\xBB ${str}`)) 41 | }, 42 | err: function(str) { 43 | console.log(clr.err(`\xBB ${str}`)) 44 | }, 45 | log: function(str) { 46 | console.log(clr.log(`\xBB ${str}`)) 47 | }, 48 | title: function() { 49 | console.log(clr.title('\xBB Welcome to Phaser Node Kit \xAB')) 50 | }, 51 | fun: function(str) { 52 | console.log(clr.fun(str)) 53 | }, 54 | dashes: function(amt) { 55 | dashes(amt) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/watch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * phaser-node-kit 3 | * @author C. Byerley 4 | * @copyright (c)2017 develephant.com 5 | * @license MIT 6 | * https://github.com/develephant/phaser-node-kit 7 | */ 8 | const { pp } = require('./utils') 9 | const fs = require('fs-extra') 10 | const path = require('path') 11 | const paths = require('./paths') 12 | const get = require('simple-get') 13 | const spawn = require('child_process').spawn 14 | const watch = require('node-watch') 15 | const opn = require('opn') 16 | 17 | const Build = require('./build') 18 | 19 | /* BUILD WATCHER */ 20 | class Watcher { 21 | constructor() { 22 | this.pnconfig = null 23 | 24 | this.compileDelay = 500 25 | this.refreshDelay = 500 26 | 27 | this.shouldRefresh = true 28 | 29 | this.compileDelayTimer = null 30 | this.refreshDelayTimer = null 31 | 32 | this.ignoredFiles = [] 33 | } 34 | 35 | isFileAllowed(filename) { 36 | let parts = path.parse(filename) 37 | 38 | let ext = parts.ext 39 | let base = parts.base 40 | 41 | let isAllowed = true 42 | this.ignoredFiles.map((restricted) => { 43 | if ((base === restricted) || (ext === restricted)) { 44 | isAllowed = false 45 | } 46 | }) 47 | 48 | return isAllowed 49 | } 50 | 51 | refresh() { 52 | if (this.shouldRefresh) { 53 | get(`http://${this.pnconfig.watch.host}:${this.pnconfig.watch.port}/__lightserver__/trigger`, (err, resp) => { 54 | if (err) { console.error(err) } 55 | }) 56 | } 57 | } 58 | 59 | //if js file found queue up compile 60 | //add a delay in case of multiple files 61 | startCompileDelay() { 62 | clearTimeout(this.compileDelayTimer) 63 | this.compileDelayTimer = setTimeout(() => { 64 | this.bundleJs() 65 | }, this.compileDelay) 66 | } 67 | 68 | //if asset files are updated, refresh browser 69 | startRefreshDelay() { 70 | clearTimeout(this.refreshDelayTimer) 71 | this.refreshDelayTimer = setTimeout(() => { 72 | this.refresh() 73 | }, this.refreshDelay) 74 | } 75 | 76 | //add asset files 77 | copyToBuild(source) { 78 | if (this.isFileAllowed(source)) { 79 | //nasty hack - fix this or no dessert. 80 | let sep = path.sep 81 | let re = new RegExp(sep+'game'+sep) 82 | let buildPath = source.replace(re, `${sep}build${sep}`) 83 | 84 | fs.copy(source, buildPath, (err) => { 85 | if (err) { 86 | pp.err(err) 87 | } else { 88 | let parts = path.parse(source) 89 | pp.ok(`Added->${parts.base}`) 90 | this.startRefreshDelay() 91 | } 92 | }) 93 | 94 | } 95 | } 96 | 97 | //remove assets files 98 | removeFromBuild(source) { 99 | //nasty hack - fix this or no dessert. 100 | let sep = path.sep 101 | let re = new RegExp(sep+'game'+sep) 102 | let buildPath = source.replace(re, `${sep}build${sep}`) 103 | 104 | fs.remove(buildPath, (err) => { 105 | if (err) { 106 | pp.err(err) 107 | } else { 108 | let parts = path.parse(source) 109 | pp.warn(`Removed->${parts.base}`) 110 | this.startRefreshDelay() 111 | } 112 | }) 113 | } 114 | 115 | //bundle the js files 116 | bundleJs() { 117 | this.builder.run() 118 | } 119 | 120 | startServer() { 121 | //spawn light-server 122 | let port = this.pnconfig.watch.port.toString() 123 | let host = this.pnconfig.watch.host 124 | let dir = paths.build 125 | 126 | const lightServer = spawn('light-server', ['-s', dir, '-p', port, '-b', host, '-q'], 127 | { cwd: path.join(paths.cli.base, 'node_modules', '.bin'), stdio: null } ) 128 | } 129 | 130 | startWatch() { 131 | watch(paths.game, { recursive: true }, (evt, filename) => { 132 | let parts = path.parse(filename) 133 | if (evt === 'update') { 134 | if (parts.ext === '.js') { 135 | this.startCompileDelay() 136 | } else { 137 | this.copyToBuild(filename) 138 | } 139 | } else if (evt === 'remove') { 140 | this.removeFromBuild(filename) 141 | } 142 | }) 143 | 144 | this.openBrowser() 145 | 146 | pp.ok('Development Mode Activated') 147 | } 148 | 149 | openBrowser() { 150 | opn(`http://${this.pnconfig.watch.host}:${this.pnconfig.watch.port}`) 151 | } 152 | 153 | run() { 154 | this.pnconfig = require(paths.config) 155 | 156 | this.ignoredFiles = this.pnconfig.ignore 157 | this.shouldRefresh = this.pnconfig.watch.refresh 158 | 159 | this.builder = new Build() 160 | 161 | this.startServer() 162 | this.startWatch() 163 | 164 | } 165 | } 166 | 167 | module.exports = Watcher 168 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phaser-node-kit", 3 | "version": "2.2.0", 4 | "description": "Rapid Game Development with PhaserJS and Node for Modern Browsers", 5 | "preferGlobal": true, 6 | "bin": { 7 | "pnkit": "cli.js", 8 | "light-server": "node_modules/.bin/light-server" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/develephant/phaser-node-kit.git" 13 | }, 14 | "keywords": [ 15 | "phaser", 16 | "phaserjs", 17 | "game", 18 | "gamedev", 19 | "browserify", 20 | "bundle", 21 | "scaffold", 22 | "framework", 23 | "html5", 24 | "mobile" 25 | ], 26 | "author": "develephant (http://www.develephant.com)", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/develephant/phaser-node-kit/issues" 30 | }, 31 | "homepage": "https://github.com/develephant/phaser-node-kit#readme", 32 | "devDependencies": {}, 33 | "dependencies": { 34 | "argparse": "^1.0.9", 35 | "browserify": "^14.1.0", 36 | "colors": "^1.1.2", 37 | "fs-extra": "^2.1.2", 38 | "light-server": "^2.0.1", 39 | "node-watch": "^0.5.2", 40 | "opn": "^5.1.0", 41 | "phaser-ce": "^2.7.7", 42 | "simple-get": "^2.4.0" 43 | }, 44 | "engines": { 45 | "node": ">=6.0.0" 46 | }, 47 | "directories": { 48 | "doc": "docs" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pnconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ "js" ], 3 | "watch": { 4 | "port": 5550, 5 | "host": "127.0.0.1", 6 | "refreshDelay": 500, 7 | "startBrowser": true 8 | } 9 | } -------------------------------------------------------------------------------- /tpl/game/css/index.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | /* Reset */ 7 | html, body, div, span, applet, object, iframe, 8 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 9 | a, abbr, acronym, address, big, cite, code, 10 | del, dfn, em, img, ins, kbd, q, s, samp, 11 | small, strike, strong, sub, sup, tt, var, 12 | b, u, i, center, 13 | dl, dt, dd, ol, ul, li, 14 | fieldset, form, label, legend, 15 | table, caption, tbody, tfoot, thead, tr, th, td, 16 | article, aside, canvas, details, embed, 17 | figure, figcaption, footer, header, hgroup, 18 | menu, nav, output, ruby, section, summary, 19 | time, mark, audio, video { 20 | margin: 0; 21 | padding: 0; 22 | border: 0; 23 | font-size: 100%; 24 | font: inherit; 25 | vertical-align: baseline; 26 | } 27 | 28 | body { 29 | background-color: #000000; 30 | } 31 | -------------------------------------------------------------------------------- /tpl/game/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/tpl/game/favicon.ico -------------------------------------------------------------------------------- /tpl/game/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/tpl/game/img/logo.png -------------------------------------------------------------------------------- /tpl/game/img/pnlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/tpl/game/img/pnlogo.png -------------------------------------------------------------------------------- /tpl/game/img/preload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/develephant/phaser-node-kit/59450a06b14d037c2cc7382fa65a5a58e12ecb62/tpl/game/img/preload.png -------------------------------------------------------------------------------- /tpl/game/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Phaser Node Kit 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /tpl/game/js/BootState.js: -------------------------------------------------------------------------------- 1 | 2 | class BootState { 3 | 4 | preload() { 5 | this.load.image('preload', 'img/preload.png') 6 | } 7 | 8 | create() { 9 | this.input.maxPointers = 1 10 | this.state.start('Preload') 11 | } 12 | 13 | update() { } 14 | render() { } 15 | } 16 | 17 | module.exports = BootState 18 | -------------------------------------------------------------------------------- /tpl/game/js/GameState.js: -------------------------------------------------------------------------------- 1 | 2 | class GameState { 3 | 4 | preload() { } 5 | 6 | create() { 7 | let pnlogo = this.add.image( 8 | this.world.centerX, 9 | this.world.centerY, 10 | 'pnlogo') 11 | 12 | pnlogo.anchor.set(.5) 13 | } 14 | 15 | update() { } 16 | render() { } 17 | } 18 | 19 | module.exports = GameState 20 | -------------------------------------------------------------------------------- /tpl/game/js/MenuState.js: -------------------------------------------------------------------------------- 1 | 2 | class MenuState { 3 | 4 | preload() { } 5 | 6 | create() { 7 | let logo = this.add.image( 8 | this.world.centerX, 9 | this.world.centerY, 10 | 'logo') 11 | 12 | logo.anchor.set(.5) 13 | 14 | this.input.onTap.addOnce((pointer) => { 15 | this.state.start('Game') 16 | }) 17 | } 18 | 19 | update() { } 20 | render() { } 21 | } 22 | 23 | module.exports = MenuState 24 | -------------------------------------------------------------------------------- /tpl/game/js/PreloadState.js: -------------------------------------------------------------------------------- 1 | 2 | class PreloadState { 3 | 4 | preload() { 5 | this.preloadBar = this.game.add.sprite( 6 | this.world.centerX, 7 | this.world.centerY, 8 | 'preload') 9 | 10 | this.preloadBar.anchor.set(.5) 11 | 12 | this.load.setPreloadSprite(this.preloadBar) 13 | 14 | this.load.image('logo', 'img/logo.png') 15 | this.load.image('pnlogo', 'img/pnlogo.png') 16 | } 17 | 18 | create() { 19 | this.state.start('MainMenu') 20 | } 21 | 22 | update() { } 23 | render() { } 24 | } 25 | 26 | module.exports = PreloadState 27 | -------------------------------------------------------------------------------- /tpl/game/js/index.js: -------------------------------------------------------------------------------- 1 | // PHASER IS IMPORTED AS AN EXTERNAL BUNDLE IN INDEX.HTML 2 | 3 | Phaser.Device.whenReady(() => { 4 | const bootState = require('./BootState') 5 | const preloadState = require('./PreloadState') 6 | const menuState = require('./MenuState') 7 | const gameState = require('./GameState') 8 | 9 | const game = new Phaser.Game(800, 600, Phaser.AUTO, 'game') 10 | 11 | game.stage.backgroundColor = 0x000000 12 | 13 | game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL 14 | game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL 15 | 16 | game.scale.setMinMax(800, 600) 17 | 18 | game.scale.pageAlignVertically = true 19 | game.scale.pageAlignHorizontally = true 20 | 21 | game.state.add('Boot', bootState) 22 | game.state.add('Preload', preloadState) 23 | game.state.add('MainMenu', menuState) 24 | game.state.add('Game', gameState) 25 | 26 | game.state.start('Boot') 27 | }) 28 | -------------------------------------------------------------------------------- /tpl/pnkit.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ ".DS_Store" ], 3 | "watch": { 4 | "port": 5550, 5 | "host": "127.0.0.1", 6 | "refresh": true, 7 | "startBrowser": true 8 | }, 9 | "debug": true 10 | } --------------------------------------------------------------------------------