Library / SDK
kaplayjs/kaplay avatar
kaplayjs/kaplay

KAPLAY: Building 2D Web Games with TypeScript Components

🦖 A JavaScript/TypeScript Game Library that feels like a game.

1,813 stars125 forksTypeScriptMIT

At a glance

What is it?
KAPLAY is an MIT-licensed JavaScript and TypeScript library for 2D browser games, aimed at developers who want an immediate canvas-based workflow without assembling a full engine stack. Its component model and KAPLAYGROUND are approachable, although the current 4000 release line is an alpha.
Who is it for?
KAPLAY suits developers building small or medium 2D browser games who prefer an immediate, component-oriented API and are comfortable working in an alpha release. It is a weaker fit for projects that require stable release guarantees, strict global-type avoidance from the outset, or an established bundle workflow.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why KAPLAY Targets Browser-Based 2D Development

KAPLAY solves the problem of assembling a playable 2D web game from rendering, input, collision, physics, object state, and event-handling code. It is aimed at JavaScript and TypeScript developers ranging from beginners learning game logic to experienced developers who want a compact API for browser projects. The README describes the project as a fun-first 2D game library rather than a general game editor or asset pipeline.

The central workflow is visible in the package metadata, which categorizes the library around game development, 2D games, physics, WebGL, and canvas. Its API exposes these concerns through functions and components. An object can render as a rectangle or sprite, occupy a position, expose a collider, respond through a physical body, carry health, and hold application-specific fields. That combination is the practical answer to KAPLAY's target problem: developers can start with a game loop and immediate feedback instead of first assembling unrelated rendering and interaction systems.

KAPLAY also provides KAPLAYGROUND, a web-based editor with more than 90 examples. That makes the library relevant to learning and quick prototypes as well as code-first development. The distinction matters. KAPLAYGROUND is a hosted place to try code, while the npm package, CDN script, and TypeScript declarations are the paths for putting code into an application.

KAPLAY Game Objects, Components, and Event Flow

A KAPLAY game begins when the application initializes a canvas context with `kaplay(...)`. `add([...])` then creates a game object from a component list. Components attach specific behavior to that object rather than requiring separate object hierarchies for each kind of entity. In the README example, `rect(40, 40)` controls rendering, `pos(100, 200)` supplies coordinates, `area()` adds a collider, `body()` makes the object respond to physics, and `health(8)` stores eight health points. A string such as `"friendly"` becomes a tag, while a plain object can carry game-specific fields.

Events connect those capabilities to application logic. The documentation shows collision behavior through `player.onCollide("enemy", ...)`, with the callback reducing `player.hp`. Per-object updates use `player.onUpdate(...)`, while tagged objects share behavior through `onUpdate("enemy", ...)`. Input is handled with callbacks such as `onKeyDown("w", ...)`. These callbacks mean game rules remain close to the objects and tags that participate in them.

The data flow is therefore straightforward. Input or collision invokes a registered callback, the callback reads or changes state such as health, direction, or `dead`, and movement components or methods apply the resulting action. Destroying an object removes it from the active scene. This is an event-oriented design, but it still uses imperative JavaScript rather than requiring a separate visual behavior editor. The README's “blocky imperative syntax” describes that choice accurately.

Creating and Running the First KAPLAY Project

The README offers `create-kaplay` as the fastest starting path. It creates a named project and directs the developer to a local Vite address and the generated `src/game.js` file.

bash
npx create-kaplay my-game

After the command creates the project, the documented development URL is `http://localhost:5173`. Open it and edit `src/game.js`, which is where the starter game code belongs.

For an existing Node.js project, the package can be installed with a package manager. This route requires a bundler such as Vite or ESBuild; the README does not provide a standalone bundler configuration beyond its documentation link.

bash
npm install kaplay

The minimal scene below sets a background. It is the shortest documented starting example and is suitable for confirming that KAPLAY initializes before assets and game rules are added.

javascript
kaplay({
    background: "#6d80fa",
});

A first visible object can be added without loading an external asset. This should produce a 40 by 40 rectangle at position 100, 200 in the game canvas.

javascript
add([
    rect(40, 40),
    pos(100, 200),
]);

The next form adds collision, physics, health, a tag, and application data to the same object. It is more representative of the library's intended workflow than the rectangle-only example.

javascript
const player = add([
    rect(40, 40),
    pos(100, 200),
    area(),
    body(),
    health(8),
    "friendly",
    {
        dir: vec2(-1, 0),
        dead: false,
        speed: 240,
    },
]);

Sprites, Tags, and Per-Frame KAPLAY Rules

KAPLAY can move from geometric shapes to image sprites without changing the component-based construction model. The README loads an image with `loadSprite`, names it `bean`, and then references that name from `sprite("bean")`. The asset URL is served by KAPLAY's site.

javascript
loadSprite("bean", "https://play.kaplayjs.com/bean.png");

add([
    sprite("bean"),
]);

These calls belong in the game setup flow, with the sprite added after the load declaration. The README does not document cancellation, retries, asset cache policy, or failure behavior for failed loads, so those details should be checked in the official documentation or validated in the target application.

Once the player exists, callbacks implement rules. This collision callback loses one health point when the player contacts an object tagged as an enemy.

javascript
player.onCollide("enemy", () => {
    player.hp--;
});

The update callback destroys the player after it reaches the bottom boundary. The comparison uses `height()`, which comes from the initialized game context.

javascript
player.onUpdate(() => {
    if (player.pos.y >= height()) {
        destroy(player);
    }
});

Tags can then organize group behavior. This callback selects every object carrying the `"enemy"` tag and moves it left by 400 pixels per update event. The separate key callback moves the player upward by 100 pixels per second while `w` is held.

javascript
onUpdate("enemy", (enemy) => {
    enemy.move(-400, 0);
});

onKeyDown("w", () => {
    player.move(0, 100);
});

The tradeoff is that movement rates, collision responses, and state changes are explicit in application code. That keeps rules visible, but a larger project must manage its own organization and avoid redundant callbacks.

Global Types, Package Imports, and the CDN Path

KAPLAY can expose global types for TypeScript through the `kaplay/global` export. The documented directive makes functions such as `vec2` available in typed code.

typescript
import "kaplay/global";

vec2(10, 10);

The README recommends configuring `tsconfig.json` instead, listing the installed declaration file under `compilerOptions.types`. This supports editors and TypeScript checking without making globals the only code style.

json
{
  "compilerOptions": {
    "types": ["./node_modules/kaplay/dist/declaration/global.d.ts"]
  }
}

For published games, the README warns against the global namespace and links to an optimization page. Module-style type imports remain available for projects that prefer explicit dependencies.

typescript
import type { TextCompOpt } from "kaplay"
import type * as KA from "kaplay"

interface MyTextCompOpt extends KA.TextCompOpt {
  fallback: string;
}

A browser-only alternative is the documented CDN script. Unlike package-manager installation, it does not require importing KAPLAY through a bundler, but it pins the script to `3001.0.12`, an older version than the package metadata's `4000.0.0-alpha.27.1`. That version difference matters when comparing examples or deciding which API line to standardize on. The CDN route also uses globals, which conflicts with the README's warning for published games.

KAPLAY Alpha Status, License, and Maintenance Cost

The repository is not archived, and its last push was on 2026-10-16. The recent release list includes `4000.0.0-alpha.27.1` dated 2026-05-12, `4000.0.0-alpha.27` dated 2026-03-19, and `4000.0.0-alpha.26` dated 2026-01-13. The repository is therefore receiving changes, but the current 4000 line is explicitly an alpha rather than a stable release line. Pinning the package and reviewing `CHANGELOG.md` during upgrades are project-specific maintenance tasks.

The package declares the MIT license, and the repository includes a `LICENSE` file. That permits use and modification under the license's conditions, although this review does not interpret legal obligations or provide legal advice. Applications still need to retain required license notices and review third-party assets separately.

The package is an ES module while also exposing CommonJS and declaration outputs. Its published files are limited to `dist/`, `kaplay.webp`, and `CHANGELOG.md`. Upgrades can therefore affect the distributed API and generated declarations, not merely examples and tests inside the repository. The TypeScript-focused build scripts, tests, and Playwright configuration indicate engineering infrastructure, but the README does not document compatibility guarantees for existing projects.

For learning, maintenance cost is modest: the tutorial path and KAPLAYGROUND reduce setup work. For production adoption, the alpha label is the main cost signal. Teams should account for API review, asset behavior, browser validation, and the possibility of changing the example code when upgrading from 3001 to 4000.

Editorial conclusion

KAPLAY suits developers building small or medium 2D browser games who prefer an immediate, component-oriented API and are comfortable working in an alpha release. It is a weaker fit for projects that require stable release guarantees, strict global-type avoidance from the outset, or an established bundle workflow. Evaluate `4000.0.0-alpha.27.1`, browser rendering behavior, asset loading, and the required bundler in the target project before adoption, because the package metadata marks this version as alpha and the README explicitly requires Vite or ESBuild for package-manager use.

Frequently asked questions

How do I install KAPLAY for a new JavaScript game?

Run `npx create-kaplay my-game` for the documented starter path, then open `http://localhost:5173` and edit `src/game.js`. For an existing project, install `kaplay` with a package manager and use a bundler such as Vite or ESBuild.

How do I add global TypeScript types in KAPLAY?

Import `kaplay/global` or list `./node_modules/kaplay/dist/declaration/global.d.ts` under `compilerOptions.types` in `tsconfig.json`. The README warns that published games may prefer to avoid the global namespace.

Can KAPLAY be used without a package manager?

Yes. The README documents a browser CDN script using `https://unpkg.com/[email protected]/dist/kaplay.js`. That route pins version 3001.0.12 rather than the current alpha version in the package metadata.

Official sources

  1. kaplayjs/kaplay on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kaplayjs-kaplay.svg)](https://hysenlabs.com/projects/kaplayjs-kaplay)

Was this useful?