Intro
Kaboom.js is a JavaScript game programming library that helps you make games fast and fun!
Quick Start
Paste this code in an html file and you're good to go
<script type="module">

// import kaboom lib
import kaboom from "https://unpkg.com/kaboom@next/dist/kaboom.mjs";

// initialize kaboom context
kaboom();

// load the default sprite "bean"
loadBean();

// add a game obj to screen, from a list of components
const froggy = add([
    sprite("bean", 32),
    pos(120, 80),
    area(),
    body(),
]);

// add a platform
add([
	pos(0, 480),
	rect(width(), 48),
	outline(4),
	solid(),
	area(),
	color(127, 200, 255),
])

// jump when user presses "space"
keyPress("space", () => {
    froggy.jump();
});

// move input focus to the game
focus();

</script>
It's recommended to code directly in browser with the Kaboom template on Replit.com
Also can be used with NPM
$ npm install kaboom
import kaboom from "kaboom";

kaboom();
Init
kaboom(conf?: KaboomConf) => KaboomCtx
Initialize kaboom context. The starting point of all kaboom games.
// this will create a blank canvas and import all kaboom functions to global
kaboom();

// init with some configs (check out #KaboomConf for full config list)
// create a game with custom dimension, but stretch to fit container, keeping aspect ratio, with a clear color
kaboom({
    width: 320,
    height: 240,
    stretch: true,
    letterbox: true,
    font: "sinko",
    clearColor: [ 0, 0, 255, ],
});

// all kaboom functions are imported to global automatically
add();
action();
keyPress();
vec2();

// can also prevent kaboom from importing all functions to global and use a context handle
const k = kaboom({ global: false });

k.add(...);
k.action(...);
k.keyPress(...);
k.vec2(...);
Game Obj
add(comps: CompList<T>) => Character<T>
Create and add a game obj to the scene, from a list of components or tags. The added and returned game obj will contain all methods from each component.
// let's add our player character to the screen
// we use a list of components to define who they are and how they actually work
const player = add([
    // it renders as a sprite
    sprite("mark"),
    // it has a position
    pos(100, 200),
    // it has a collider
    area(),
    // it is a physical body which will respond to physics
    body(),
    // you can easily make custom components to encapsulate reusable logics
    doubleJump(),
    health(8),
    // give it tags for controlling group behaviors
    "player",
    "friendly",
    // plain objects fields are directly assigned to the game obj
    {
        dir: vec2(-1, 0),
        dead: false,
        speed: 240,
    },
]);

// .jump is provided by body()
player.jump();

// .moveTo is provided by pos()
player.moveTo(100, 200);

// run something every frame
// player will constantly move towards player.dir, at player.speed per second
player.action(() => {
    player.move(player.dir.scale(player.speed));
});

// .collides is provided by area()
player.collides("tree", () => {
    destroy(player);
});

// run this for all game objs with tag "friendly"
action("friendly", (friend) => {
    // .hurt is provided by health()
    friend.hurt();
});

// check out #Character for stuff that exists for all game objects, independent of its components.
get(tag?: Tag) => Character[]
Get a list of all game objs with certain tag.
// get a list of all game objs with tag "bomb"
const allBombs = get("bomb");

// without args returns all current objs in the game
const allObjs = get();
every(t: Tag, cb: (obj: Character) => T)
Run callback on every game obj with certain tag.
// how destroyAll() works
every("fruit", destroy);

// without tag it runs through every game obj
every((obj) => {});
every(cb: (obj: Character) => T)
revery(t: Tag, cb: (obj: Character) => T)
Run callback on every game obj with certain tag in reverse order.
revery(cb: (obj: Character) => T)
readd(obj: Character) => Character
Remove and re-add the game obj.
// mainly useful when you want to make something to draw on top
readd(froggy);
destroy(obj: Character)
Remove the game obj.
// every time froggy collides with anything with tag "fruit", remove it
froggy.collides("fruit", (fruit) => {
    destroy(fruit);
});
destroyAll(tag: Tag)
Remove all game objs with certain tag.
// destroy all objects with tag "bomb" when you click one
clicks("bomb", () => {
    destroyAll("bomb");
});
Components
pos(x: number, y: number) => PosComp
Position
// this game obj will draw the "froggy" sprite at (100, 200)
add([
    pos(100, 200),
    sprite("froggy"),
]);
pos(xy: number) => PosComp
pos(p: Vec2) => PosComp
pos() => PosComp
scale(x: number, y: number) => ScaleComp
Scale.
scale(xy: number) => ScaleComp
scale(s: Vec2) => ScaleComp
scale() => ScaleComp
rotate(a: number) => RotateComp
Rotation (in degrees). (This doesn't work with the area() collider yet)
color(r: number, g: number, b: number) => ColorComp
Sets color (rgb 0-255).
// blue frog
add([
    sprite("froggy"),
    color(0, 0, 255)
]);
color(c: Color) => ColorComp
color() => ColorComp
opacity(o?: number) => OpacityComp
Sets opacity (0.0 - 1.0).
sprite(spr: string | SpriteData, conf?: SpriteCompConf) => SpriteComp
Renders as sprite.
// minimal setup
add([
    sprite("froggy"),
]);

// with config
const froggy = add([
    sprite("froggy", {
        // start with animation "idle"
        anim: "idle",
    }),
]);

// play / stop an anim
froggy.play("jump");
froggy.stop();

// manually setting a frame
froggy.frame = 3;
text(txt: string, conf?: TextCompConf) => TextComp
Renders as text.
// a simple score counter
const score = add([
    text("Score: 0"),
    pos(24, 24),
    { value: 0 },
]);

player.collides("coin", () => {
    score.value += 1;
    score.text = "Score:" + score.value;
});

// set to another default font on start up ("sink" is a pixel font provided by default)
kaboom({ font: "sink" });
rect(w: number, h: number) => RectComp
Renders as rect.
// i don't know, could be an obstacle or somethign
add([
    rect(20, 40),
    outline(4),
    area(),
]);
area(conf?: AreaCompConf) => AreaComp
Collider. Will calculate from rendered comps (e.g. from sprite, text, rect) if no params given.
add([
    sprite("froggy"),
    // without args it'll auto calculate from the data sprite comp provides
    area(),
]);

add([
    sprite("bomb"),
    // scale to 0.6 of the sprite size
    area({ scale: 0.6 }),
    // we want the scale to be calculated from the center
    origin("center"),
]);

// define custom area with topleft and botright point
const player = add([
    sprite("froggy"),
    area({ width: 20, height: 40. }),
])

// die if player collides with another game obj with tag "tree"
player.collides("tree", () => {
    destroy(player);
});

// push player out of all other game obj with "solid" component
player.action(() => {
    player.pushOutAll();
});

// simple drag an drop
let draggin = false;

player.clicks(() => {
    draggin = true;
});

player.action(() => {
    if (draggin) {
        player.pos = mousePos();
    }
})

mouseRelease(() => {
    draggin = false;
});

// check for collision with another single game obj
player.action(() => {
    if (player.isColliding(bomb)) {
        score += 1;
    }
});

// for more methods check out AreaComp
origin(o: Origin | Vec2) => OriginComp
Origin point for render (default "topleft").
// set origin to "center" so it'll rotate from center
add([
    rect(40, 10),
    rotate(45),
    origin("center"),
]);
layer(l: string) => LayerComp
Which layer this object belongs to.
z(z: number) => ZComp
Determines the draw order for objects on the same layer. Object will be drawn on top if z value is bigger.
outline(width?: number, color?: Color) => OutlineComp
Give obj an outline.
body(conf?: BodyCompConf) => BodyComp
Physical body that responds to gravity. Requires "area" and "pos" comp. This also makes the object "solid".
// froggy jumpy
const froggy = add([
    sprite("froggy"),
    // body() requires "pos" and "area" component
    pos(),
    area(),
    body(),
]);

// when froggy is grounded, press space to jump
// check out BodyComp for more methods
keyPress("space", () => {
    if (froggy.grounded()) {
        froggy.jump();
    }
});

// a custom event provided by "body"
froggy.on("ground", () => {
    debug.log("oh no!");
});
solid() => SolidComp
Make other objects cannot move pass. Requires "area" comp.
move(direction: number | Vec2, speed: number) => MoveComp
Move towards a direction infinitely, and destroys when it leaves game view. Requires "pos" comp.
// enemy throwing feces at player
const projectile = add([
    sprite("feces"),
    pos(player.pos),
    area(),
    move(player.pos.angle(enemy.pos), 1200),
]);
follow(obj: Character | null, offset?: Vec2) => FollowComp
Follow another game obj's position.
shader(id: string) => ShaderComp
Custom shader.
timer(n?: number, action?: () => void) => TimerComp
Run certain action after some time.
fixed() => FixedComp
Unaffected by camera.
// this score counter better be fixed on top left and not affected by camera
const score = add([
    text(0),
    pos(12, 12),
]);
stay() => StayComp
Don't get destroyed on scene switch.
player.collides("bomb", () => {
    // spawn an explosion and switch scene, but don't destroy the explosion game obj on scene switch
    add([
        sprite("explosion", { anim: "burst", }),
        stay(),
        lifespan(2),
    ]);
    go("lose", score);
});
health(hp: number) => HealthComp
Handles health related logic and events.
const player = add([
    health(3),
]);

player.collides("bad", (bad) => {
    player.hurt(1);
    bad.hurt(1);
});
 
player.collides("apple", () => {
    player.heal(1);
});

player.on("hurt", () => {
    play("ouch");
});

// triggers when hp reaches 0
player.on("death", () => {
    destroy(player);
    go("lose");
});
lifespan(time: number, action?: () => void) => LifespanComp
Destroy the game obj after certain amount of time
// spawn an explosion, destroy after 2 seconds and the switch scene
add([
    sprite("explosion", { anim: "burst", }),
    lifespan(2, () => go("lose")),
]);
Events
on(event: string, tag: Tag, cb: (obj: Character, args: ...) => void) => EventCanceller
Register an event on all game objs with certain tag.
// a custom event defined by body() comp
// every time an obj with tag "bomb" hits the floor, destroy it and addKaboom()
on("ground", "bomb", (bomb) => {
    destroy(bomb);
    addKaboom();
});
action(tag: Tag, cb: (obj: Character) => void) => EventCanceller
Register "update" event (runs every frame) on all game objs with certain tag.
// move every "tree" 120 pixels per second to the left, destroy it when it leaves screen
// there'll be nothing to run if there's no "tree" obj in the scene
action("tree", (tree) => {
    tree.move(-120, 0);
    if (tree.pos.x < 0) {
        destroy(tree);
    }
});

// without tags it just runs it every frame
action(() => {
    debug.log("ohhi");
});
action(cb: () => void) => EventCanceller
render(tag: Tag, cb: (obj: Character) => void) => EventCanceller
Register "draw" event (runs every frame) on all game objs with certain tag. (This is the same as `action()`, but all draw events are run after updates)
render(cb: () => void) => EventCanceller
collides(t1: Tag, t2: Tag, cb: (a: Character, b: Character, side?: RectSide) => void) => EventCanceller
Register event when 2 game objs with certain tags collides. This function spins off an action() when called, please put it at root level and never inside another action().
collides("sun", "earth", () => {
    addExplosion();
});
clicks(tag: Tag, cb: (a: Character) => void) => EventCanceller
Register event when game objs with certain tags are clicked. This function spins off an action() when called, please put it at root level and never inside another action().
hovers(tag: Tag, cb: (a: Character) => void) => EventCanceller
Register event when game objs with certain tags are hovered. This function spins off an action() when called, please put it at root level and never inside another action().
Input
mousePos() => Vec2
Get current mouse position (without camera transform).
mouseWorldPos() => Vec2
Get current mouse position (after camera transform)
mouseDeltaPos() => Vec2
How much mouse moved last frame.
keyDown(k: Key | Key[], cb: () => void) => EventCanceller
Registers an event that runs every frame when a key is down.
// move left by SPEED pixels per frame every frame when "left" is being held down
keyDown("left", () => {
    froggy.move(-SPEED, 0);
});
keyPress(k: Key | Key[], cb: () => void) => EventCanceller
Registers an event that runs when user presses certain key.
// .jump() once when "space" is just being pressed
keyPress("space", () => {
    froggy.jump();
});
keyPress(cb: () => void) => EventCanceller
keyPressRep(k: Key | Key[], cb: () => void) => EventCanceller
Registers an event that runs when user presses certain key (also fires repeatedly when they key is held).
// delete last character when "backspace" is being pressed and held
keyPressRep("backspace", () => {
    input.text = input.text.substring(0, input.text.length - 1);
});
keyPressRep(cb: () => void) => EventCanceller
keyRelease(k: Key | Key[], cb: () => void) => EventCanceller
Registers an event that runs when user releases certain key.
keyRelease(cb: () => void) => EventCanceller
charInput(cb: (ch: string) => void) => EventCanceller
Registers an event that runs when user inputs text.
// export type into input
charInput((ch) => {
    input.text += ch;
});
mouseDown(cb: (pos: Vec2) => void) => EventCanceller
Registers an event that runs every frame when mouse button is down.
mouseClick(cb: (pos: Vec2) => void) => EventCanceller
Registers an event that runs when user clicks mouse.
mouseRelease(cb: (pos: Vec2) => void) => EventCanceller
Registers an event that runs when user releases mouse.
mouseMove(cb: (pos: Vec2) => void) => EventCanceller
Registers an event that runs whenever user move the mouse.
touchStart(cb: (id: TouchID, pos: Vec2) => void) => EventCanceller
Registers an event that runs when a touch starts.
touchMove(cb: (id: TouchID, pos: Vec2) => void) => EventCanceller
Registers an event that runs whenever touch moves.
touchEnd(cb: (id: TouchID, pos: Vec2) => void) => EventCanceller
Registers an event that runs when a touch ends.
keyIsDown(k: Key) => boolean
If certain key is currently down.
// almost equivalent to the keyPress() example above
action(() => {
    if (keyIsDown("left")) {
        froggy.move(-SPEED, 0);
    }
});
keyIsPressed(k?: Key) => boolean
If certain key is just pressed last frame.
keyIsPressedRep(k?: Key) => boolean
If certain key is just pressed last frame (accepts help down repeatedly).
keyIsReleased(k?: Key) => boolean
If certain key is just released last frame.
mouseIsDown() => boolean
If certain mouse is currently down.
mouseIsClicked() => boolean
If mouse is just clicked last frame.
mouseIsReleased() => boolean
If mouse is just released last frame.
mouseIsMoved() => boolean
If mouse moved last frame.
Assets
loadRoot(path?: string) => string
Sets the root for all subsequent resource urls.
loadRoot("https://myassets.com/");
loadSprite("froggy", "sprites/froggy.png"); // will resolve to "https://myassets.com/sprites/frogg.png"
loadSprite(id: string | null, src: SpriteLoadSrc, conf?: SpriteLoadConf) => Promise<SpriteData>
Load a sprite into asset manager, with name and resource url and optional config.
// due to browser policies you'll need a static file server to load local files
loadSprite("froggy", "froggy.png");
loadSprite("apple", "https://kaboomjs.com/sprites/apple.png");

// slice a spritesheet and add anims manually
loadSprite("froggy", "froggy.png", {
    sliceX: 4,
    sliceY: 1,
    anims: {
        run: {
            from: 0,
            to: 3,
        },
        jump: {
            from: 3,
            to: 3,
        },
    },
});
loadSpriteAtlas(src: SpriteLoadSrc, data: SpriteAtlasData) => Promise<Record<string, SpriteData>>
Load sprites from a sprite atlas.
loadSpriteAtlas("sprites/dungeon.png", {
    "hero": {
        x: 128,
        y: 68,
        width: 144,
        height: 28,
        sliceX: 9,
        anims: {
            idle: { from: 0, to: 3 },
            run: { from: 4, to: 7 },
            hit: { from: 8, to: 8 },
        },
    },
});

const player = add([
    sprite("hero"),
]);

player.play("run");

// or load from json file, see SpriteAtlasData export type for format spec
loadSpriteAtlas("sprites/dungeon.png", "sprites/dungeon.json");
loadSpriteAtlas(src: SpriteLoadSrc, url: string) => Promise<Record<string, SpriteData>>
loadAseprite(name: string | null, imgSrc: SpriteLoadSrc, jsonSrc: string) => Promise<SpriteData>
Load a sprite with aseprite spritesheet json.
loadAseprite("car", "sprites/car.png", "sprites/car.json");
loadPedit(name: string, src: string) => Promise<SpriteData>
loadBean(name?: string) => Promise<SpriteData>
Load default sprite "bean".
loadBean();

// use it right away
add([
    sprite("bean"),
]);
loadSound(id: string, src: string) => Promise<SoundData>
Load a sound into asset manager, with name and resource url.
loadSound("shoot", "horse.ogg");
loadSound("shoot", "https://kaboomjs.com/sounds/scream6.mp3");
loadFont(id: string, src: string, gridWidth: number, gridHeight: number, conf?: FontLoadConf) => Promise<FontData>
Load a bitmap font into asset manager, with name and resource url and infomation on the layout of the bitmap.
// load a bitmap font called "04b03", with bitmap "fonts/04b03.png"
// each character on bitmap has a size of (6, 8), and contains default ASCII_CHARS
loadFont("04b03", "fonts/04b03.png", 6, 8);

// load a font with custom characters
loadFont("cp437", "cp437.png", 6, 8, "☺☻♥♦♣♠");
loadShader(name: string, vert?: string, frag?: string, isUrl?: boolean) => Promise<ShaderData>
Load a shader into asset manager with vertex and fragment code / file url.
// load only a fragment shader from URL
loadShader("outline", null, "/shaders/outline.glsl", true);

// default shaders and custom shader format
loadShader("outline",
    `vec4 vert(vec3 pos, vec2 uv, vec4 color) {
    // predefined functions to get the default value by kaboom
    return def_vert();
}`,
`vec4 frag(vec3 pos, vec2 uv, vec4 color, sampler2D tex) {
    // turn everything blue-ish
    return def_frag() * vec4(0, 0, 1, 1);
}`, true);
load(l: Promise<T>)
Add a new loader to wait for before starting the game.
load(new Promise((resolve, reject) => {
    // anything you want to do that stalls the game in loading state
    resolve("ok");
}));
Info
width() => number
Get the width of game.
height() => number
Get the height of game.
center() => Vec2
Get the center point of view.
// add froggy to the center of the screen
add([
    sprite("froggy"),
    pos(center()),
    // ...
]);
dt() => number
Get the delta time since last frame.
// rotate froggy 100 deg per second
froggy.action(() => {
    froggy.angle += 100 * dt();
});
time() => number
Get the total time since beginning.
screenshot() => string
Take a screenshot and get the dataurl of the image.
focused() => boolean
If the game canvas is currently focused.
focus()
Focus on the game canvas.
ready(cb: () => void)
Run something when assets finished loading.
const froggy = add([
    // ...
]);

// certain assets related data are only available when the game finishes loading
ready(() => {
    debug.log(froggy.numFrames());
});
isTouch() => boolean
Is currently on a touch screen device.
shake(intensity: number)
Camera shake.
// shake intensively when froggy collides with a "bomb"
froggy.collides("bomb", () => {
    shake(120);
});
camPos(pos: Vec2) => Vec2
Get / set camera position.
// camera follows player
player.action(() => {
    camPos(player.pos);
});
camScale(scale: Vec2) => Vec2
Get / set camera scale.
camRot(angle: number) => number
Get / set camera rotation.
toScreen(p: Vec2) => Vec2
Transform a point from world position to screen position.
toWorld(p: Vec2) => Vec2
Transform a point from screen position to world position.
gravity(g: number) => number
Get / set gravity.
layers(list: string[], def?: string)
Define layers (the last one will be on top).
// defining 3 layers, "ui" will be drawn on top most, with default layer being "game"
layers([
    "bg",
    "game",
    "ui",
], "game");

// use layer() comp to define which layer an obj belongs to
add([
    text(score),
    layer("ui"),
    fixed(),
]);

// without layer() comp it'll fall back to default layer, which is "game"
add([
    sprite("froggy"),
]);
loop(t: number, cb: () => void) => EventCanceller
Run the callback every n seconds.
// spawn a bomb at random position every frame
loop(1, () => {
    add([
        sprite("bomb"),
        pos(rand(0, width()), rand(0, height())),
        area(),
        body(),
    ]);
});
wait(n: number, cb?: () => void) => Promise<void>
Run the callback after n seconds.
cursor(c?: Cursor) => Cursor
Get / set the cursor (css). Cursor will be reset to "default" every frame so use this in an per-frame action.
hovers("clickable", (c) => {
    cursor("pointer");
});
regCursor(c: string, draw: string | ((mpos: Vec2) => void))
Load a cursor from a sprite, or custom drawing function.
loadSprite("froggy", "sprites/froggy.png");

// use sprite as cursor
regCursor("default", "froggy");
regCursor("pointer", "apple");
fullscreen(f?: boolean) => boolean
Enter / exit fullscreen mode.
// toggle fullscreen mode on "f"
keyPress("f", (c) => {
    fullscreen(!fullscreen());
});
Audio
play(id: string, conf?: AudioPlayConf) => AudioPlay
Play a piece of audio, returns a handle to control.
// play a one off sound
play("wooosh");

// play a looping soundtrack (check out AudioPlayConf for more configs)
const music = play("OverworldlyFoe", {
    volume: 0.8,
    loop: true
});

// using the handle to control (check out AudioPlay for more controls / info)
music.pause();
music.play();
burp(conf?: AudioPlayConf) => AudioPlay
Yep.
volume(v?: number) => number
Sets global volume.
// makes everything quieter
volume(0.5);
audioCtx: AudioContext
Get the underlying browser AudioContext.
Math
rand() => number
Get a random number (with optional bounds).
// a random number between 0 - 1
rand();

// a random number between 0 - 8
rand(8);

// a random number between 50 - 100
rand(50, 100);

// a random vec2 between vec2(0) and vec2(100)
rand(vec2(0), vec2(100));

// spawn something on the right side of the screen but with random y value within screen height
add([
    pos(width(), rand(0, height())),
]);
rand(n: T) => T
rand(a: T, b: T) => T
randi() => number
rand() but integer only.
randi(n: T) => T
randi(a: T, b: T) => T
randSeed(seed?: number) => number
Get / set the random number generator seed.
vec2(x: number, y: number) => Vec2
Make a 2d vector.
// { x: 0, y: 0 }
vec2();

// { x: 10, y: 10 }
vec2(10);

// { x: 100, y: 80 }
const pos = vec2(100, 80);

// move to 150 degrees direction with by length 10
pos = pos.add(dir(150).scale(10));
vec2(p: Vec2) => Vec2
vec2(xy: number) => Vec2
vec2() => Vec2
rgb(r: number, g: number, b: number) => Color
RGB color (0 - 255).
quad(x: number, y: number, w: number, h: number) => Quad
Rectangle area (0.0 - 1.0).
choose(lst: T[]) => T
Choose a random item from a list.
// decide the best fruit randomly
const bestFruit = choose(["apple", "banana", "pear", "watermelon"]);
chance(p: number) => boolean
rand(1) <= p
// every frame all objs with tag "unlucky" have 50% chance die
action("unlucky", (o) => {
    if (chance(0.5)) {
        destroy(o);
    }
});
lerp(from: number, to: number, t: number) => number
Linear interpolation.
map(v: number, l1: number, h1: number, l2: number, h2: number) => number
Map a value from one range to another range.
mapc(v: number, l1: number, h1: number, l2: number, h2: number) => number
Map a value from one range to another range, and clamp to the dest range.
dir(deg: number) => Vec2
Get directional vector from an angle
// move towards 80 deg direction at SPEED
player.action(() => {
    player.move(dir(80).scale(SPEED));
});
wave(lo: number, hi: number, t: number) => number
Sin() motion between 2 values.
// change color with sin() like motion
action("colorful", (c) => {
    c.color.r = wave(0, 255, time());
    c.color.g = wave(0, 255, time() + 1);
    c.color.b = wave(0, 255, time() + 2);
});
deg2rad(deg: number) => number
Convert degrees to radians.
rad2deg(rad: number) => number
Convert radians to degrees.
rng(seed: number) => RNG
Make a new random number generator.
colLineLine(l1: Line, l2: Line) => Vec2 | null
colRectRect(r1: Rect, r2: Rect) => boolean
Scene
scene(id: SceneID, def: SceneDef)
Define a scene.
go(id: SceneID, args: ...)
Go to a scene, passing all rest args to scene callback.
Level
addLevel(map: string[], conf: LevelConf) => Level
Construct a level based on symbols.
// example from demo/platformer.js
addLevel([
    "                          $",
    "                          $",
    "                          $",
    "           $$         =   $",
    "  %      ====         =   $",
    "                      =   $",
    "                      =    ",
    "       ^^      = >    =    ",
    "===========================",
], {
    // define the size of each block
    width: 32,
    height: 32,
    // define what each symbol means, by a function returning a comp list (what you'll pass to add())
    "=": () => [
        sprite("floor"),
        area(),
        solid(),
    ],
    "$": () => [
        sprite("coin"),
        area(),
        pos(0, -9),
    ],
    "^": () => [
        sprite("spike"),
        area(),
        "danger",
    ],
});
Data
getData(key: string, def?: T) => T
Get data from local storage, if not present can set to a default value.
setData(key: string, data: any)
Set data from local storage.
Render
drawSprite(id: string | SpriteData, conf?: DrawSpriteConf)
Draw a sprite.
drawText(txt: string, conf?: {

}
)
drawRect(pos: Vec2, w: number, h: number, conf?: DrawRectConf)
drawRectStroke(pos: Vec2, w: number, h: number, conf?: DrawRectStrokeConf)
drawLine(p1: Vec2, p2: Vec2, conf?: DrawLineConf)
drawTri(p1: Vec2, p2: Vec2, p3: Vec2, conf?: DrawTriConf)
plug(plugin: KaboomPlugin<T>)
Import a plugin.
Misc
debug: Debug
Debug stuff.
// pause the whole game
debug.paused = true;

// enter inspect mode
debug.inspect = true;

// in debug mode (on by default, unless disabled by `debug: false` in KaboomConf), some keys are binded to toggle certain debug features:
// F1: toggle debug.inspect
// F2: call debug.clearLog()
// F8: toggle debug.pause
// F7: decrease debug.timeScale
// F9: increase debug.timeScale
// F10: call debug.stepFrame()
ASCII_CHARS: string
All chars in ASCII.
CP437_CHARS: string
All chars in CP437.
LEFT: Vec2
Left directional vector vec2(-1, 0).
UP: Vec2
Up directional vector vec2(0, -1).
DOWN: Vec2
Down directional vector vec2(0, 1).
canvas: HTMLCanvasElement
The canvas DOM kaboom is currently using.
Types
KaboomCtx
Context handle that contains every kaboom function.
Tag
string
CompList
Array<T | Tag>
Key
"f1" | "f2" | "f3" | "f4" | "f5" | "f6" | "f7" | "f8" | "f9" | "f10" | "f11" | "f12" | "`" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "0" | "-" | "=" | "q" | "w" | "e" | "r" | "t" | "y" | "u" | "i" | "o" | "p" | "[" | "]" | "\" | "a" | "s" | "d" | "f" | "g" | "h" | "j" | "k" | "l" | ";" | "'" | "z" | "x" | "c" | "v" | "b" | "n" | "m" | "," | "." | "/" | "backspace" | "enter" | "tab" | "space" | " " | "left" | "right" | "up" | "down"
CharacterInspect
Inspect info for a character.
Record<Tag, string | null>
KaboomConf
Kaboom configurations.
width?: number
height?: number
scale?: number
stretch?: boolean
letterbox?: boolean
debug?: boolean
font?: string
crisp?: boolean
canvas?: HTMLCanvasElement
root?: HTMLElement
clearColor?: number[]
inspectColor?: number[]
texFilter?: TexFilter
logMax?: number
touchToMouse?: boolean
global?: boolean
plugins?: KaboomPlugin<any>[]
KaboomPlugin
(k: KaboomCtx) => T
Character
A character in game. The basic unit of object in Kaboom. The player, a bullet, a tree, a piece of text, they're all characters!
{
    _id: number | null
    hidden: boolean
    paused: boolean
    exists() => boolean
    is(tag: Tag | Tag[]) => boolean
    use(comp: Comp | Tag)
    unuse(comp: Tag)
    action(cb: () => void) => EventCanceller
    on(ev: string, cb: () => void) => EventCanceller
    trigger(ev: string, args: ...)
    destroy()
    c(id: Tag) => Comp
    inspect() => CharacterInspect
} & MergeComps<T>
SceneID
string
SceneDef
(args: ...) => void
TouchID
number
EventCanceller
Cancel the event.
() => void
SpriteAnim
Frame-based animation configuration.
number | {
    from: number
    to: number
    loop?: boolean
    pingpong?: boolean
    speed?: number
}
SpriteAnimPlayConf
Sprite animation configuration when playing.
loop?: boolean
pingpong?: boolean
speed?: number
onEnd?: () => void
SpriteAnims
A dict of name <-> animation.
Record<string, SpriteAnim>
SpriteLoadConf
Sprite loading configuration.
sliceX?: number
sliceY?: number
anims?: SpriteAnims
filter?: TexFilter
wrap?: TexWrap
SpriteAtlasData
Record<string, SpriteAtlasEntry>
SpriteAtlasEntry
A sprite in a sprite atlas.
x: number
y: number
width: number
height: number
sliceX?: number
sliceY?: number
anims?: SpriteAnims
SpriteLoadSrc
string | GfxTexData
SpriteData
tex: GfxTexture
frames: Quad[]
anims: SpriteAnims
filter?: TexFilter
wrap?: TexWrap
FontLoadConf
chars?: string
filter?: TexFilter
wrap?: TexWrap
SoundData
buf: AudioBuffer
FontData
ShaderData
AudioPlayConf
Audio play configurations.
loop?: boolean
volume?: number
speed?: number
detune?: number
seek?: number
AudioPlay
play(seek?: number)
stop()
pause()
paused() => boolean
stopped() => boolean
speed(s?: number) => number
detune(d?: number) => number
volume(v?: number) => number
time() => number
duration() => number
loop()
unloop()
GfxProgram
bind()
unbind()
bindAttribs()
send(uniform: Uniform)
GfxTexture
width: number
height: number
bind()
unbind()
GfxTexData
HTMLImageElement | HTMLCanvasElement | ImageData | ImageBitmap
GfxFont
tex: GfxTexture
map: Record<string, Vec2>
qw: number
qh: number
Vertex
pos: Vec3
uv: Vec2
color: Color
opacity: number
TexFilter
Texture scaling filter. "nearest" is mainly for sharp pixelated scaling, "linear" means linear interpolation.
"nearest" | "linear"
TexWrap
"repeat" | "clampToEdge"
GfxTexConf
filter?: TexFilter
wrap?: TexWrap
RenderProps
pos?: Vec2
scale?: Vec2 | number
rot?: number
color?: Color
opacity?: number
origin?: Origin | Vec2
z?: number
prog?: GfxProgram
uniform?: Uniform
DrawQuadConf
RenderProps & {
    flipX?: boolean
    flipY?: boolean
    width?: number
    height?: number
    tex?: GfxTexture
    quad?: Quad
}
DrawTextureConf
RenderProps & {
    flipX?: boolean
    flipY?: boolean
    width?: number
    height?: number
    tiled?: boolean
    quad?: Quad
}
DrawRectStrokeConf
RenderProps & {
    width?: number
}
DrawRectConf
DrawLineConf
RenderProps & {
    width?: number
}
DrawTriConf
DrawTextConf
RenderProps & {
    size?: number
    width?: number
}
FormattedChar
tex: GfxTexture
quad: Quad
ch: string
pos: Vec2
scale: Vec2
color: Color
opacity: number
origin: string
FormattedText
width: number
height: number
chars: FormattedChar[]
Cursor
string | "auto" | "default" | "none" | "context-menu" | "help" | "pointer" | "progress" | "wait" | "cell" | "crosshair" | "text" | "vertical-text" | "alias" | "copy" | "move" | "no-drop" | "not-allowed" | "grab" | "grabbing" | "all-scroll" | "col-resize" | "row-resize" | "n-resize" | "e-resize" | "s-resize" | "w-resize" | "ne-resize" | "nw-resize" | "se-resize" | "sw-resize" | "ew-resize" | "ns-resize" | "nesw-resize" | "nwse-resize" | "zoom-int" | "zoom-out"
Origin
"topleft" | "top" | "topright" | "left" | "center" | "right" | "botleft" | "bot" | "botright"
DrawSpriteConf
RenderProps & {
    frame?: number
    width?: number
    height?: number
    tiled?: boolean
    flipX?: boolean
    flipY?: boolean
    quad?: Quad
    prog?: ShaderData
    uniform?: Uniform
}
Vec2
x: number
y: number
clone() => Vec2
add(p: Vec2) => Vec2
add(x: number, y: number) => Vec2
sub(p: Vec2) => Vec2
sub(x: number, y: number) => Vec2
scale(p: Vec2) => Vec2
scale(s: number) => Vec2
scale(sx: number, sy: number) => Vec2
dot(p: Vec2) => number
dist(p: Vec2) => number
len() => number
unit() => Vec2
normal() => Vec2
angle(p: Vec2) => number
lerp(p: Vec2, t: number) => Vec2
toFixed(n: number) => Vec2
eq(p: Vec2) => boolean
str() => string
Vec3
x: number
y: number
z: number
xy() => Vec2
Vec4
x: number
y: number
z: number
w: number
Mat4
m: number[]
clone() => Mat4
mult(m: Mat4) => Mat4
multVec4(m: Vec4) => Vec4
multVec3(m: Vec3) => Vec3
multVec2(m: Vec2) => Vec2
scale(s: Vec2) => Mat4
translate(p: Vec2) => Mat4
rotateX(a: number) => Mat4
rotateY(a: number) => Mat4
rotateZ(a: number) => Mat4
invert() => Mat4
Color
0-255 RGBA color.
r: number
g: number
b: number
clone() => Color
lighten(n: number) => Color
darken(n: number) => Color
invert() => Color
eq(c: Color) => boolean
str() => string
Quad
x: number
y: number
w: number
h: number
scale(q: Quad) => Quad
clone() => Quad
eq(q: Quad) => boolean
RNGValue
number | Vec2 | Color
RNG
seed: number
gen() => number
gen(n: T) => T
gen(a: T, b: T) => T
Rect
p1: Vec2
p2: Vec2
Line
p1: Vec2
p2: Vec2
ClientID
number
MsgHandler
(id: ClientID, data: any) => void
Comp
id?: Tag
require?: Tag[]
add?: () => void
load?: () => void
update?: () => void
draw?: () => void
destroy?: () => void
inspect?: () => string
CharacterID
number
PosComp
pos: Vec2
move(xVel: number, yVel: number)
move(vel: Vec2)
moveBy(dx: number, dy: number)
moveBy(d: Vec2)
moveTo(dest: Vec2, speed?: number)
moveTo(x: number, y: number, speed?: number)
screenPos() => Vec2
ScaleComp
scale: Vec2
scaleTo(s: number)
scaleTo(s: Vec2)
scaleTo(sx: number, sy: number)
RotateComp
angle: number
ColorComp
color: Color
OpacityComp
opacity: number
OriginComp
origin: Origin | Vec2
LayerComp
layer: string
ZComp
z: number
FollowComp
follow: {
    obj: Character
    offset: Vec2
}
MoveComp
RectSide
"top" | "bottom" | "left" | "right"
AreaCompConf
offset?: Vec2
width?: number
height?: number
scale?: number | Vec2
cursor?: Cursor
AreaComp
area: AreaCompConf
areaWidth() => number
areaHeight() => number
isClicked() => boolean
isHovering() => boolean
isColliding(o: Character) => boolean
isTouching(o: Character) => boolean
clicks(f: () => void)
hovers(onHover: () => void, onNotHover?: () => void)
collides(tag: Tag, f: (obj: Character, side?: RectSide) => void)
hasPt(p: Vec2) => boolean
pushOut(obj: Character)
pushOutAll()
worldArea() => Rect
screenArea() => Rect
SpriteCompConf
quad?: Quad
frame?: number
tiled?: boolean
width?: number
height?: number
anim?: string
animSpeed?: number
flipX?: boolean
flipY?: boolean
SpriteComp
width: number
height: number
frame: number
quad: Quad
play(anim: string, conf?: SpriteAnimPlayConf)
stop()
numFrames() => number
curAnim() => string
animSpeed: number
flipX(b: boolean)
flipY(b: boolean)
TextComp
text: string
textSize: number
font: string | FontData
width: number
height: number
TextCompConf
size?: number
font?: string | FontData
width?: number
RectComp
width: number
height: number
AreaType
"rect" | "line" | "point" | "circle" | "polygon"
OutlineComp
lineWidth: number
lineColor: Color
Debug
paused: boolean
inspect: boolean
timeScale: number
showLog: boolean
fps() => number
objCount() => number
drawCalls() => number
stepFrame()
clearLog()
log(msg: string)
error(msg: string)
UniformValue
Uniform
Record<string, UniformValue>
ShaderComp
uniform: Uniform
shader: string
BodyComp
solid: boolean
jumpForce: number
weight: number
curPlatform() => Character | null
grounded() => boolean
falling() => boolean
jump(force?: number)
djump(f?: number)
BodyCompConf
jumpForce?: number
maxVel?: number
weight?: number
solid?: boolean
Timer
time: number
action()
TimerComp
wait(n: number, cb: () => void) => EventCanceller
SolidComp
solid: boolean
FixedComp
fixed: boolean
StayComp
stay: boolean
HealthComp
hurt(n?: number)
heal(n?: number)
hp() => number
setHP(hp: number)
LifespanComp
LifespanCompConf
fade?: number
LevelConf
width: number
height: number
pos?: Vec2
any(s: string) => CompList<any> |
Level
getPos(p: Vec2) => Vec2
getPos(x: number, y: number) => Vec2
spawn(sym: string, p: Vec2) => Character
spawn(sym: string, x: number, y: number) => Character
width() => number
height() => number
gridWidth() => number
gridHeight() => number
offset() => Vec2
destroy()
Custom Component