By participating in this project you agree to abide by the terms in the Contributor Code of Conduct.
The goal of Kontra is not to implement everything you could possibly need to make a game. There are already libraries out there that do that (like Phaser).
Instead, Kontra aims to implement basic game requirements like asset loading, input, the game loop, and spites to keep the library very small and focused. This allows it to be used when your game size is limited (like the js13k games competition).
Below is a list of features the library will not support or add:
- Physics engine
- Math helpers
- Linear transformations
To help keep the code small the library follows some unconventional code patterns. Take a look at these byte-saving techniques and follow these recommendations:
- Prefer
==
over===
(save a byte) - Prefer
!=
over==
(save a byte) - Prefer
| 0
overMath.floor()
- Prefer
let
overconst
(save a byte) - Prefer
Array.map()
overArray.forEach()
The library uses eslint to help enforce these codes styles. To run eslint, run npm run eslint
.
To build the development code, run npm run build
. To build the distribution version of the code, run npm run dist
.
Please add unit and/or integration tests for all new changes, as well as TypeScript tests found in test/typings. To run the tests, run npm test
. To run the TypeScript tests, run npm run test:ts
.
The TypeScript tests just ensure that the TypeScript declaration file is correct and doesn't miss any obvious use cases with the various APIs.
Some unit test files contain a testContext
object which allows the suite to run tests conditionally when features are turned on or removed. When changing code in these types of suites, please pay attention to if the test should only run when a feature is enabled or removed.
Please update the export files for all new changes (if need be). kontra.defaults.js imports all functionality and then adds it to the kontra
object. kontra.js exports all functionality directly. You will also need to add tests to their respected spec files to ensure the functionality is exported.
The documentation and the TypeScript declaration file are built from the JSDoc-like comments in the source files using LivingCSS (I know, not what it was intended for but it makes it really easy to build multiple pages of docs. And it's highly configurable). Both are built when running npm run build
.
To update the documentation or the declaration file, just modify the JSDoc-like comments. The comments are not true JSDoc syntax, but a modified version that supports both JSDoc tags and TypeSript declarations. For example, a comment for an object will be declared using TypeSript for the JSDoc type.
/**
* @param {{x: number, y: number}} [properties.anchor={x:0,y:0}] - The x and y origin of the game object. {x:0, y:0} is the top left corner of the game object, {x:1, y:1} is the bottom right corner.
*/
The documentation will automatically read the TypeScript type and say it's an Object, while the declaration file will take the type directly.
<!-- docs -->
<dt>
<code>properties.anchor</code>
<span class="optional">Optional</span>
</dt>
<dd>
<p>Object. The x and y origin of the game object. {x:0, y:0} is the top left corner of the game object, {x:1, y:1} is the bottomright corner. Defaults to <code>{x:0,y:0}</code>.
</p>
</dd>
// kontra.d.ts
interface GameObject{
anchor: {x: number, y: number};
}
All documentation related gulp tasks and @tag
information can be found in tasks/doc.js. All TypeScript related gulp tasks and @tag
information can be found in tasks/typescript.js.
Use uppercase for the first letter of each basic type: Number
, Boolean
, String
, Object
, Function
.
If the type is a Function
and takes no arguments and doesn't return anything, use Function
. Otherwise declare the arguments and return using the syntax (params: Type) => ReturnType
.
/**
* @param {(dt?: Number) => void} update - Function called every frame to update the game. Is passed the fixed `dt` as a parameter.
* @param {Function} render - Function called every frame to render the game.
*/
If the type is an Object and can take any number of properties, use Object
. Otherwise declare the properties of the object using the syntax {key: Type}
.
/**
* @param {Object} [properties] - Properties of the quadtree.
* @param {{x: Number, y: Number, width: Number, height: Number}} [properties.bounds] - The 2D space (x, y, width, height) the quadtree occupies. Defaults to the entire canvas width and height.
*/