Kontra.js
repository·main·Indexed 21 days ago
https://github.com/straker/kontraA lightweight JavaScript micro-library for HTML5 game development, specifically optimized for the size constraints of the js13kGames competition. It provides essential game development tools including animation systems, accessible UI buttons, a spatial layout Grid class, and a comprehensive Gamepad API.
What's inside kontra
- Kontra.js is a lightweight JavaScript gaming micro-library. It is specifically optimized for use in the js13kGames competition, where file size constraints are critical.
Access Kontra.js documentation
mainComprehensive documentation for the Kontra.js library, including API references and guides, is hosted externally at the project's GitHub Pages site.Customize child alignment with alignSelf and justifySelf
mainWhile the
Griddefines global alignment for its rows and columns, individual child objects can override this behavior using two properties:alignSelf: Overrides the grid's vertical (align) alignment for that specific child.justifySelf: Overrides the grid's horizontal (justify) alignment for that specific child.
Valid values for both are
'start','center', and'end'.Initialize the Gamepad API
mainBefore using any gamepad functions, you must call
initGamepad(). This sets up the necessary event listeners for gamepad connections and updates the gamepad state every frame using the internaltickevent.Note: Gamepad support requires a secure context (HTTPS). Additionally, because gamepad state must be checked every frame, you should use the
GameLoopprovided by Kontra.js to ensure the state is updated automatically.import { initGamepad, GameLoop } from 'kontra'; // Must be called first initGamepad(); // Using GameLoop ensures gamepad state is updated automatically every frame let loop = GameLoop({ update: function() { // your game logic } }); loop.start();Create a Scene with Scene()
mainUse the
Scenefactory function to organize a group of objects that will update and render together. A scene manages a collection of objects, a camera for viewport control, and an accessible DOM node for screen readers.Configuration Options
When creating a scene, you can pass an options object with the following properties:
id(String): The unique identifier for the scene.name(String, optional): A human-friendly name used for screen reader accessibility. Defaults toid.objects(Object[], optional): An initial array of objects to add to the scene.context(CanvasRenderingContext2D, optional): The canvas context to draw to. Defaults to the result ofcore.getContext().cullObjects(Boolean, optional): Iftrue, objects outside the camera bounds will not be rendered. Defaults totrue.cullFunction(Function, optional): The function used to filter objects for rendering. Defaults tohelpers.collides.sortFunction(Function, optional): The function used to sort objects before rendering (e.g., for depth sorting).onShow(Function, optional): Callback triggered when the scene is shown.onHide(Function, optional): Callback triggered when the scene is hidden.props(Object, optional): Any additional properties to be assigned to the scene instance.
import { Scene, Sprite } from 'kontra'; const sprite = Sprite({ x: 100, y: 200, width: 20, height: 40, color: 'red' }); const scene = Scene({ id: 'game', objects: [sprite] }); scene.render();Animate a Sprite using SpriteSheet animations
mainTo use animations, pass an
animationsobject to theSpriteconstructor. This object should containAnimationinstances (usually obtained from aSpriteSheet).When animations are provided:
- The sprite automatically clones each animation so that multiple sprites can use the same sheet without interfering with each other's playback state.
- The
currentAnimationis set to the first animation in the list by default. - You can switch between animations using
playAnimation(name). - The sprite's
widthandheightwill default to the dimensions of the animation frames if not explicitly set.
import { Sprite, SpriteSheet } from 'kontra'; let spriteSheet = SpriteSheet({ // ... configuration for spriteSheet animations: { idle: { frames: 1, loop: false, }, walk: { frames: [1, 2, 3] } } }); let sprite = Sprite({ x: 100, y: 200, animations: spriteSheet.animations }); // Play a specific animation by name sprite.playAnimation('idle');Initialize a Quadtree
mainA
Quadtreeis a 2D spatial partitioning data structure used to group objects by their position to optimize collision detection and spatial queries. You can initialize it using the default factory function or theQuadtreeClassconstructor.To prevent excessive garbage collection, the quadtree acts like an object pool: it creates subnodes as needed but does not destroy them when the tree collapses. Therefore, you should call
.clear()every frame instead of re-instantiating the tree.import Quadtree from 'kontra'; // Using the default factory let quadtree = Quadtree({ maxDepth: 3, maxObjects: 25, bounds: { x: 0, y: 0, width: 800, height: 600 } });Initialize the TileEngine
mainThe
TileEngineis used to manage and render tile-based maps. It uses an off-screen canvas to pre-render tiles for performance. You can initialize it by passing a properties object containing map dimensions, tile dimensions, tilesets, and layers.Properties:
width(Number): Width of the tile map in number of tiles.height(Number): Height of the tile map in number of tiles.tilewidth(Number): Width of a single tile in pixels.tileheight(Number): Height of a single tile in pixels.context(CanvasRenderingContext2D, optional): The context to draw to. Defaults tocore.getContext().tilesets(Object[], required): Array of tileset objects.layers(Object[], required): Array of layer objects.
Tileset Object Properties:
firstgid(Number): First tile index of the tileset (the first tileset should havefirstgid: 1).image(String|HTMLImageElement): Path to the image or the element itself. If a path is used, it must be pre-loaded viaassets.load.spacing(Number, default: 0): Whitespace between tiles in pixels.margin(Number, default: 0): Whitespace border around the tileset image.tilewidth(Number, optional): Width of the tileset tile. Defaults to enginetilewidth.tileheight(Number, optional): Height of the tileset tile. Defaults to enginetileheight.columns(Number, optional): Number of columns in the tileset image.source(String, optional): Path to a Tiled JSON source file (must be pre-loaded).
Layer Object Properties:
name(String): Unique name of the layer.data(Number[]): 1D array of tile indices.visible(Boolean, default: true): Whether the layer is drawn.opacity(Number, default: 1): Layer opacity (0 to 1).
import { TileEngine } from 'kontra'; let tileEngine = TileEngine({ tilewidth: 32, tileheight: 32, width: 4, height: 4, tilesets: [{ firstgid: 1, image: myLoadedImage }], layers: [{ name: 'background', data: [ 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 ] }] });Initialize keyboard input with initKeys()
mainBefore using any keyboard-related functions in Kontra, you must call
initKeys(). This function sets up the necessary global event listeners forkeydown,keyup, andblur, and populates the defaultkeyMapwith alpha (a-z) and numeric (0-9) keys.import { initKeys } from 'kontra'; initKeys();Use the Grid class for spatial layouts
mainThe
Gridclass allows you to organize UI elements into structured layouts (columns, rows, or grids) similar to CSS Grid Layout. It automatically calculates the positions of child objects based on properties like flow, alignment, gaps, and breakpoints.To use it, instantiate it via the
Gridfactory function and pass a configuration object. You can then add child objects usingaddChild().import Grid from './grid.js'; const grid = Grid({ flow: 'grid', numCols: 3, colGap: 10, rowGap: 10, align: 'center', justify: 'start' }); grid.addChild(someGameObject); // The grid will automatically position 'someGameObject' based on the settings above.Configure Grid properties
mainWhen initializing a
Grid, you can provide the following properties to control its layout behavior:Property Type Default Description flowString'column'How to organize objects: 'column'(single column),'row'(single row), or'grid'(usesnumCols).alignString | String[]'start'Vertical alignment of the grid. Values: 'start','center','end'. An array allows alternating alignment per row (e.g.,['end', 'start']).justifyString | String[]'start'Horizontal alignment of the grid. Values: 'start','center','end'. An array allows alternating alignment per column.colGapNumber | Number[]0Horizontal gap between columns. An array allows alternating gaps per column. rowGapNumber | Number[]0Vertical gap between rows. An array allows alternating gaps per row. numColsNumber1Number of columns. Only applies if flowis set to'grid'.dirString''Direction of the grid. Set to 'rtl'for right-to-left organization.breakpointsArray<{metric: Function, callback: Function}>[]Responsive settings that trigger a callbackwhen ametricfunction returns true.Extend the gamepad button map
mainBy default,
gamepadMapmaps standard hardware indices to human-readable names (e.g.,0: 'south'). You can extend or modify this map to support custom buttons or non-standard controllers by assigning a name to a new index.Note: This must be done before checking button states.
import { gamepadMap, gamepadPressed } from 'kontra'; // Map index 2 to a custom name gamepadMap[2] = 'buttonWest'; if (gamepadPressed('buttonWest')) { // handle custom button }