Changelog
All notable changes to this project will be documented in this file.
The format is (mostly) based on Keep a Changelog, and this project adheres to Semantic Versioning.
[4000.0.0] - TBD
Added
-
Added
ellipse()
component. -
Added circle and (rotated) ellipse collision shapes.
-
Added
clipLineToRect()
-
Added support to circle shapes in
area()
. -
Added
obj.setParent()
to change the parent of a game object. -
Added
fakeMouse()
to create a fake mouse cursor.const myCursor = add([fakeMouse(), sprite("kat"), pos(100, 100)]); myCursor.press(); // trigger onClick events if the mouse is over myCursor.release(); myCursor.move(vec2(100, 200)); // move as your wish
-
Added restitution and friction.
-
Added
k.system()
to replace internal events or create new.system("collision", () => { // system code }, [LCEvents.AfterFixedUpdate, LCEvents.AfterUpdate]),
-
Added LCEvents enum for identify different lifecycle events.
Changed
- Replaced the Separating Axis Theorem (SAT) with the “Gilbert–Johnson–Keerthi”
(
GJK
) distance algorithm. - Changed default behaviour of
kaplay({ tagsAsComponents: false })
tofalse
.
[3001.0.5] - 2024-12-18
Added
- Added tags and components separation in
KAPLAYOpt.tagsAsComponents
(experimental) - Added
.is()
,.tag()
and.untag()
toGameObjRaw
, check, add and remove (experimental) - Added
.has()
toGameObjRaw
, to check if a game object has a component tags (experimental) - Added events for listen to comps being removed or added
onUse()
andonUnused()
(experimental) - Added
k.cancel()
to cancel the current event (experimental) -
onKeyPress("space", () => { // do something // cancel the event return cancel(); });
- Added
getDefaultLayer()
to get the default layer (experimental) - Added
getLayers()
to get the layers list (experimental) - Added many JSDoc specifiers on many functions (@require, @deprecated, @since, @group, etc)
Changed
- Added
.use()
,.unuse()
and.has()
toGameObjRaw
, to add, remove and check components. This only works withKAPLAYOpt.tagsAsComponents
set totrue
(experimental)
Deprecated
- Deprecated camera methods
camScale()
,camPos()
andcamRot()
in favor ofsetCamScale()
,getCamScale()
,setCamPos()
,getCamPos()
,setCamRot()
andgetCamRot
. - Deprecated
camTransform()
in favor ofgetCamTransform()
. - Deprecated
camFlash()
in favor offlash()
, for ashake()
-like name.
Fixed
- Fixed artifacts present in some TrueType fonts.
- Fixed
.use()
and.unuse()
with area components.
[3001.0.0] “Spooky Beans!” - 2024-10-31
Input
-
Added input bindings,
onButtonPress
,onButtonRelease
,onButtonDown
, and it’s corresponding boolean versions,isButtonPressed
,isButtonDown
andisButtonReleased
.kaplay({ // bind your buttons buttons: { jump: { keyboard: ["space", "up"], keyboardCode: "Space", // you can also use key codes gamepad: ["south"], }, }, }); onButtonPress("jump", () => { player.jump(); });
-
added
getButton(btn)
andsetButton(btn)
to get and set button bindings// ["space", "up"] debug.log(getButton("jump").keyboard); // change the jump button in keyboard to "w" setButton("jump", { keyboard: ["w"], // gamepad binding is not changed });
-
added
getLastInputDeviceType()
to get what was the last pressed deviceonButtonPress(() => { const lastInputDevice = getLastInputDeviceType(); // keyboard, mouse or gamepad // change icons, etc });
-
added
pressButton(btn)
andreleaseButton(btn)
to simulate button press and releasepressButton("jump"); // triggers onButtonPress and starts onButtonDown releaseButton("jump"); // triggers onButtonRelease and stops onButtonDown
-
added the possibility of use arrays in all input handlers
onKeyPress(["w", "up"], () => { player.jump(); });
-
now gamepad events return what gamepad triggered the action
onGamepadButtonPress("south", (btn, gp) => { console.log(gp.index); // gamepad number on navigator's gamepad list });
Physics
- added effector components:
areaEffector()
,buoyancyEffector()
,pointEffector()
,surfaceEffector()
. - added
constantForce()
component. - added
patrol()
component to move along a list of waypoints. - added
sentry()
component to notify when certain objects are in sight. - added
NavMesh
class for pathfinding on a mesh. - added
pathfinder()
component to calculate a list of waypoints on a graph. - now collision checks are only done if there’s area objects.
Game Object
-
added
getTreeRoot()
to get the game’s root object, which is the parent of all other objects// get the root object const root = getTreeRoot(); root.add(); // same as add() root.get(); // same as get()
-
added
GameObjRaw.tags
to get a game object’s tags.const obj = add([sprite("bean"), "enemy", "dangerous"]); // get the tags debug.log(obj.tags); // ["enemy", "dangerous"]
Components
-
added support to setters/getters syntax in
ScaleComp
andSpriteComp
componentsconst obj = add([sprite("bean"), scale(2)]); // set it with = syntax obj.scale = vec2(3, 4); obj.sprite = "bag";
Rendering and Animation
-
added the
animate()
component to animate the properties of an object using keyframes. Check out Animation Example// prop to animate, frames, options rotatingBean.animate("angle", [0, 360], { duration: 2, direction: "forward", });
-
added
particles()
component to emit and draw particles. -
readded
layers()
and thelayer()
component.Before the
z()
component, there was alayer()
component that allowed you to control the draw order of objects. It was removed in v3000, but now it’s back from the void.// define the layers layers( [ "bg", "game", "ui", // the default layer ], "game", ); // use the layer component add([sprite("bg"), layer("bg")]);
-
added
SpriteComp.getCurAnim()
to get the current animation dataconst obj = add([sprite("bean", { anim: "walk" })]); // get the current animation name debug.log(obj.getCurAnim().name); // "walk"
-
added
SpriteComp.getAnim()
for get any animation dataloadSprite("bean", "bean.png", { sliceX: 4, sliceY: 1, anims: { walk: { from: 0, to: 3, }, }, }); const obj = add([sprite("bean")]); // get the animation data debug.log(obj.getAnim("walk")); // { from: 0, to: 3 }
-
added
SpriteComp.hasAnim()
to check if an animation existsconst obj = add([sprite("bean", { anim: "walk" })]); // check if an animation exists debug.log(obj.hasAnim("walk")); // true
-
added
camFlash()
to flash the screen.camFlash(0.5, 0.5, 0.5, 0.5);
-
added support for radius in individual corners for
RectComp
component.add([ rect(100, 100, { radius: [10, 20, 30, 40], }), ]);
-
(! break) removed compatibilty to use two KAPLAY frames in the same page, due to perfomance improvements
-
fix error screen not showing with not Error object
-
Added
SpriteComp.animFrame
to get the frame of the current animation (not on the spritesheet)
Audio
-
now you can pass an
AudioBuffer
toloadSound()
-
added
loadMusic()
to load streaming audio (doesn’t block in loading screen).loadMusic("bgm", "bgm.mp3"); // play the music play("bgm");
Math
-
added
Vec2.fromArray()
to convert an array to aVec2
.const point = Vec2.fromArray([100, 200]); // vec2(100, 200);
-
added
Vec2.toArray()
to convert aVec2
to an array.const point = vec2(100, 200); const arr = point.toArray(); // [100, 200]
-
added
chooseMultiple()
to choose a random element from an array.const numbers = [1, 2, 3, 4, 5]; const random = chooseMultiple(numbers, 3); // [3, 1, 5]
-
added
shuffle()
to shuffle an array.const numbers = [1, 2, 3, 4, 5]; shuffle(numbers); // [3, 1, 5, 2, 4]
Debug mode
-
added
outline()
,shader()
, andarea()
properties todebug.inspect
. -
added
KAPLAYOpt.debugKey
for customizing the key used to toggle debug mode.kaplay({ debugKey: "l", });
-
added compatibility with custom properties in debug mode
const obj = add([ sprite("bean"), { health: 100, // on debug.inspect damage: 10, // on debug.inspect hp() { this.health -= this.damage; }, // not on debug.inspect }, ]); // see the custom properties in debug mode debug.inspect = true;
-
Now
debug.log()
accepts multiple argument of any type, likeconsole.log()
.
Helpers
- added
getSceneName()
to get the current scene name - added
Color.toArray()
to convert a color to an array - added global raycast function and raycast method to level
- added support for textured polygons
- added support for concave polygon drawing
- added support for arrays in uniforms
- added support for texture larger than 2048x2048
- added support for gravity direction
- added line join (bevel, miter, round) and line caps (square, round)
- added quadratic bezier and Catmull-Rom evaluation
- added evaluation of the first and second derivatives for all splines
- added higher order easing functions linear, steps and cubic-bezier
TypeScript
-
Now you can type
get()
with a type parameter and passing component types. (v4000)const player = get<BodyComp>("player");
-
Now
Key
also accepts a string as an acceptable value. -
Now
text()
component doesn’t require to pass a string. -
Now
camScale()
andcamPos()
accept only 1 number as parameter. -
Now
shake()
can be called without args. -
Now
loadShader()
andloadShaderURL()
accepts null for unused parameters. -
Now
RectCompOpt
accepts a array of numbers forradius
.
Deprecations
All changes applies for both v3001 and v4000
- deprecated
kaboom()
in favor ofkaplay()
(you can still usekaboom*
) - deprecated
SpriteComp.curAnim()
in favor ofSpriteComp.getCurAnim().name
- deprecated
fadeIn
component in favor ofOpacityComp.fadeIn()
- deprecated
Event
,EventHandler
andEventController
in favor ofKEvent
,KEventHandler
andKEventController
Bug fixes
All changes applies for both v3001 and v4000
- (break) much typescript definitions was fixed, if you use typescript now maybe you see new errors that make your code strict
- fix error screen not showing with not Error object
- fix error where debug screen was scaling bad the blue rectangles
- fix error where error screen was not showing when the error was thrown in a input event
- fix error where fonts was cropped in the bottom
- fix an error where
stay()
object loose their input events on scene change
v3000.1.17
- exposed
vel
property onBodyComp
v3000.1.16
- fixed error not being logged
- fixed error screen scaling error in letterbox mode
v3000.1.15
- fixed
loadRoot()
not working sometimes - fixed audio being resumed when the tab is switched on but
debug.paused
is true
v3000.1.12
- fixed
color()
andrgb()
not working
v3000.1.11
- added option
kaboom({ focus: false })
to disable focus on start - fixed
rand()
typing for numbers - fixed mouse position in fullscreen
- added
Color#toHSL()
v3000.1.10
- fixed test code accidentally getting shipped (where a screenshot will be downloaded every time you press space)
v3000.1.9
- added
fill
option torect()
,circle()
andsprite()
- fixed view getting cut off in letterbox mode
v3000.1.8
- fixed
scale
option acting weird when width and height are defined (by @hirnsalat)
v3000.1.7
- fixed
debug.paused
not pausing audio - added
mask()
component - added support for colored font outline
loadFont("apl386", "/examples/fonts/apl386.ttf", {
outline: {
width: 8,
color: rgb(0, 0, 255),
},
});
- fixed
wave()
not starting at0
when time is0
- kaboom now only displays error screen for kaboom’s own error, instead of catching all errors in current window
- added
KaboomError
class for errors related to current kaboom instance - setting
obj.text
withtext()
component now immediately updateswidth
andheight
property
const obj = add([text("oh hi"), pos(100, 200)]);
// before
obj.text = "bye";
console.log(obj.width); // still the width of "oh hi" until next render
// before
obj.text = "bye";
console.log(obj.width); // will be updated to the width of "bye"
v3000.1.6
- fixed
loadSound
typing to acceptArrayBuffer
v3000.1.5
- added
Event#clear()
method - fixed
add()
without argument
v3000.1.4
- added
audio.stop()
method
const music = play("music");
music.stop();
v3000.1.3
- fixed
onCollideUpdate()
still runs when object is paused - allow
add()
andmake()
without arguments - added
debug.numObjects()
- added
width
andheight
properties toSpriteData
// get sprite size
getSprite("bean").then((spr) => {
console.log(spr.width, spr.height);
});
v3000.1.2
- fixed audio not pausing when tab hidden and
backgroundAudio
not set - fixed
debug.timeScale
not working - fixed
debug.paused
not able to resume - fixed
quad
option not working insprite()
component - added
onHide()
andonShow()
for tab visibility event
v3000.1.1
- fixed some indirect
fixed
related issues
[3000.1.0] - 2023-08-18 (kaboom.js)
- added game object level input handling
// add a scene game object
const scene = add([]);
const bean = scene.add([sprite("bean"), pos(100, 200), area(), body()]);
scene.onKeyPress("space", () => {
bean.jump();
});
scene.onMousePress(() => {
bean.jump();
});
// setting scene.paused will pause all the input events
scene.paused = true;
// destroying scene will cancel all its input events
scene.destroy();
const ui = add([]);
ui.add(makeButton());
// these will only work if ui game object is active
ui.onMousePress(() => {
// ...
});
// before you'll have to manually clean up events on obj.onDestroy()
const scene = add([]);
const evs = [];
scene.onDestroy(() => {
evs.forEach((ev) => ev.cancel());
});
evs.push(
k.onKeyPress("space", () => {
doSomeSceneSpecificStuff();
}),
);
- added
make()
to create game object without adding to the scene
const obj = make([sprite("bean"), pos(120, 60)]);
add(obj);
- fixed children not inheriting
fixed()
from parent
// before
const ui = add([fixed()]);
ui.add([
rect(),
// have to also give all children game objects fixed()
fixed(),
]);
// now
const ui = add([fixed()]);
// you don't have to add fixed() to children
ui.add([rect(100, 100)]);
- fixed
AreaComp#onClick()
event not getting cleaned up when game object is destroyed - fixed typo
isTouchScreen()
->isTouchscreen()
- fixed inspect mode doesn’t show the properties box of indirect children game objects
- fixed some problem causing kaboom to not work with vite
- fixed “destroy” event not run on children game objects
- calling
shake()
when another shake is happening adds to the shake instead of reset it? - fixed incorrect touch position when canvas is not at top left of page
[3000.0.0] - 2023-05-25 (kaboom.js)
Game Objects
- added scene graph, game objects are now stored in a tree-like structure and
can have children with
obj.add()
const bean = add([sprite("bean"), pos(160, 120)]);
const sword = bean.add([
sprite("sword"),
// transforms will be relative to parent bean object
pos(20, 20),
rotate(20),
]);
const hat = bean.add([
sprite("hat"),
// transforms will be relative to parent bean object
pos(0, -10),
]);
// children will be moved alongside the parent
bean.moveBy(100, 200);
// children will be destroyed alongside the parent
bean.destroy();
- added
recursive
andliveUpdate
options toget()
const enemies = get("enemy", {
// get from all children and descendants, instead of only direct children
recursive: true,
// live update the returned list to listen to onAdd and onDestroy events
liveUpdate: true,
});
console.log(enemies.length); // 3
add([sprite("bigbird"), "enemy"]);
console.log(enemies.length); // 4
- changed object update order from reversed to not reversed
- (BREAK) removed
GameObj#every()
andGameObj#revery()
in favor ofobj.get("*").forEach()
- (BREAK) renamed
GameObj#_id
toGameObj#id
addLevel()
now returns aGameObj
which has all individual grid objects as its children game objects, withLevelComp
containing its previous methods- added
onAdd()
andonDestroy()
events to listen to added / destroyed game objects
Components
- added support for getter and setters in component properties
Area
- added collision support for rotate shapes and polygons
- added option
collisionIgnore
toarea()
component, which accepts a list of tags to ignore when checking collision
const bean = add([
sprite("bean"),
pos(100, 80),
area({
collisionIgnore: ["cloud", "particle"],
}),
]);
- added
Area#getCollisions
to get a list of all current collisions happening
for (const col of player.getCollisions()) {
const c = col.target;
if (c.is("chest")) {
c.open();
}
}
- added
Area#onCollideUpdate()
andonCollideUpdate()
to register an event that runs every frame when 2 objects are colliding - added
Area#onCollideEnd()
andonCollideEnd()
to register an event that runs once when 2 objects stop colliding - added
Area#onHover()
andonHover()
to register an event that runs once when an object(s) is hovered over - added
Area#onHoverEnd()
andonHoverEnd()
to register an event that runs once when an object(s) stops being hovered over - (BREAK) renamed
onHover()
toonHoverUpdate()
(it registers an event that runs every frame when an object is hovered over) - (BREAK) renamed
pushOut()
toresolveCollision()
Body
- added
Body#onFall()
which fires when object starts falling - added
Body#onPhysicsResolve()
andBody#onBeforePhysicsResolve()
to register events relating to collision resolution
// make semi-solid platforms that doesn't block player when player is jumping over it
player.onBeforePhysicsResolve((collision) => {
if (collision.target.is(["platform", "soft"]) && player.isJumping()) {
collision.preventResolution();
}
});
- (BREAK) removed
solid()
in favor ofbody({ isStatic: true })
- added option
body({ mass: 3 })
to define how hard a non-static body is to be pushed by another non-static body - added option
body({ stickToPlatform: false })
to turn off object moving with platform - (BREAK) removed
Body#doubleJump()
in favor ofdoubleJump()
component - (BREAK) renamed
Body#weight
toBody#gravityScale
- (BREAK) renamed
Body#onFall()
toBody#onFallOff()
which triggers when object fall off a platform - (BREAK) defining
setGravity()
is now required for enabling gravity,body()
by default will only prevent objects from going through each other
Others
- (BREAK) renamed
origin()
toanchor()
, so it won’t mess up typescript in global mode - (BREAK)
anchor
(previouslyorigin
) no longer controls text alignment, usetext({ align: "left" })
option instead - added
doubleJump()
component to enable double jump (or any number of jumps) - (BREAK) renamed
outview()
tooffscreen()
, and uses a much faster check (but less accurate) for if object is offscreen- removed
offset
option in favor of a simplerdistance
option - renamed
onExitView()
andonEnterView()
toonExitScreen()
andonEnterScreen()
- removed
- (BREAK) removed
cleanup()
component in favor ofoffscreen({ destroy: true })
- added
OpacityComp#fadeOut()
- added
fadeIn()
component stay()
now accepts a list of scenes to stay for, likestay(["gameover", "menu"])
- (BREAK) changed
SpriteComp#flipX
andSpriteComp#flipY
to properties instead of functions - (BREAK)
sprite.onAnimStart()
andsprite.onAnimEnd()
now triggers on any animation
// before
obj.onAnimEnd("walk", () => {
// do something
});
// v3000
obj.onAnimEnd((anim) => {
if (anim === "walk") {
// do something
}
});
- (BREAK)
ScaleComp#scale
will always be aVec2
notnumber
shader()
compuniform
parameter now supports a callback that returns the uniform every frame
const player = add([
sprite("bean"),
// will calculate and send u_time every frame
shader("flashy", () => ({
u_time: time(),
})),
]);
Assets
- added
loadProgress()
that returns a0.0 - 1.0
that indicates current asset loading progress - added option
loadingScreen
tokaboom()
where you can turn off the default loading screen - added
onLoadUpdate()
to register a custom loading screen (see “loader” example)
// custom loading screen
onLoadUpdate((progress) => {
drawCircle({
pos: center(),
radius: 32,
end: map(progress, 0, 1, 0, 360),
});
});
- added support for multiple sprite sources as frames in
loadSprite()
loadSprite("player", [
"sprites/player_idle.png",
"sprites/player_run.png",
"sprites/player_jump.png",
]);
- (BREAK) added
loadShaderURL()
,loadShader()
now only load shader code not files
Text
- added
loadFont()
to load.ttf
,.otf
,.woff2
or any font supported by browserFontFace
// Load a custom font from a .ttf file
loadFont("FlowerSketches", "/examples/fonts/FlowerSketches.ttf");
// Load a custom font with options
loadFont("apl386", "/examples/fonts/apl386.ttf", {
outline: 4,
filter: "linear",
});
- (BREAK) renamed previous
loadFont()
toloadBitmapFont()
- (BREAK) removed built-in
apl386
,apl386o
,sink
,sinko
(still available underexamples/fonts
) - changed default font size to
36
- (BREAK) changed to bbcode syntax for styled text
// before
"[oh hi].green here's some [styled].wavy text";
// v3000
"[green]oh hi[/green] here's some [wavy]styled[/wavy] text";
Graphics
- fixed visual artifacts on text rendering
- added
colors
option todrawPolygon()
that controls the color of each corner - added
gradient
option todrawRect()
that specifies the start and end color - added
drawMasked()
anddrawSubtracted()
- added
pushRotateX()
,pushRotateY()
andpushRotateZ()
- added
pixelDensity
option tokaboom()
- (BREAK) changed position vertex format from
vec3
tovec2
(which is passed in as the first argument of customfrag
andvert
shader functions) - added
usePostEffect()
to add post process shader
loadShader(
"invert",
null,
`
vec4 frag(vec2 pos, vec2 uv, vec4 color, sampler2D tex) {
vec4 c = def_frag();
return vec4(1.0 - c.r, 1.0 - c.g, 1.0 - c.b, c.a);
}
`,
);
usePostEffect("invert");
- shader error logs now yields the correct line number
- added
slice9
option toloadSprite()
to enable 9 slice scaling
loadSprite("grass", "/sprites/grass.png", {
slice9: {
left: 8,
right: 8,
top: 8,
bottom: 8,
},
});
const g = add([sprite("grass")]);
onMouseMove(() => {
const mpos = mousePos();
// updating width / height will scale the image but not the sliced frame
g.width = mpos.x;
g.height = mpos.y;
});
Audio
- added option
kaboom({ backgroundAudio: false })
to not pause audio when tab not active - changed
speed
,detune
,volume
,loop
inAudioPlay
from functions to properties - added
onEnd()
event forconst pb = play("sound")
// before
const music = play("song");
music.speed(2);
music.volume(0.5);
music.loop(true);
// v3000
const music = play("song");
music.speed = 2;
music.volume = 0.5;
music.loop = true;
Input
- added
onScroll(action: (delta: Vec2) => void)
to listen mouse wheel scroll - fixed touches not treated as mouse
- (BREAK) changed
onTouchStart()
,onTouchMove()
andonTouchEnd()
callback signature to(pos: Vec2, touch: Touch) => void
(exposes the nativeTouch
object) - added
onGamepadButtonPress()
,onGamepadButtonDown()
,onGamepadButtonRelease()
- added
isGamepadButtonPressed()
,isGamepadButtonDown()
,isGamepadButtonReleased()
- added
onGamepadStick()
to handle gamepad axes info for left and right sticks - added
getConnectedGamepads()
- added
onGamepadConnect()
andonGamepadDisconnect()
- added
gamepads
option tokaboom()
to define custom gamepads
Level
- (BREAK) changed
addLevel()
options API- renamed
width
andheight
totileWidth
andtileHeight
- renamed
any
towildcardTile
- now all tile symbols are defined in the
tiles
object
- renamed
// before
addLevel(["@ ^ $$", "======="], {
width: 32,
height: 32,
"=": () => [sprite("grass"), area(), body({ isStatic: true })],
$: () => [sprite("coin"), area(), "coin"],
any: (symbol) => {
if (symbol === "@") {
return [
/* ... */
];
}
},
});
// v3000
addLevel(["@ ^ $$", "======="], {
tileWidth: 32,
tileHeight: 32,
tiles: {
"=": () => [sprite("grass"), area(), body({ isStatic: true })],
$: () => [sprite("coin"), area(), "coin"],
},
wildcardTile: (symbol) => {
if (symbol === "@") {
return [
/* ... */
];
}
},
});
Misc
- sprites are now automatically packed, improving performance
- (BREAK) renamed
gravity()
intogetGravity()
andsetGravity()
- (BREAK) removed all deprecated functions in v2000.2
- (BREAK) raised esbuild target to
esnext
- added
setBackground()
andgetBackground()
in addition tobackground
option inkaboom()
- moved type defs for global functions to
import "kaboom/global"
// if use global functions
import "kaboom";
import "kaboom/global"; // required to load global types
kaboom();
// will have definition
add();
// if don't use global function
import "kaboom";
kaboom({ global: false });
// type error, won't pollute global namespace if not manually import "kaboom/global"
add();
- added
tween()
for tweening, and a set of built-in easing functions ineasings
onMousePress(() => {
tween(
bean.pos.x,
mousePos().x,
1,
(val) => (bean.pos.x = val),
easings.easeOutBounce,
);
tween(
bean.pos.y,
mousePos().y,
1,
(val) => (bean.pos.y = val),
easings.easeOutBounce,
);
});
- (BREAK) changed all event handlers to return a
EventController
object instead of a function to cancel event
// before
const cancel = onUpdate(() => {
/* ... */
});
cancel();
// v3000
const ev = onUpdate(() => {
/* ... */
});
ev.paused = true;
ev.cancel();
- timers can now be paused
const timer = wait(4, () => {
/* ... */
});
timer.paused = true;
timer.resume();
const timer = loop(1, () => {
/* ... */
});
timer.paused = true;
timer.resume();
kaboom()
now automatically focuses the canvas- added
quit()
to end everything - added
download()
,downloadText()
,downloadJSON()
,downloadBlob()
- added
Recording#stop()
to stop the recording and returns the video data as mp4 Blob - added
debug.numFrames()
to get the total number of frames elapsed - added
onError()
to handle error or even custom error screen - added
onResize()
to register an event that runs when canvas resizes - added
setCursorLocked()
andisCursorLocked()
- (BREAK) renamed
cursor()
tosetCursor()
- (BREAK) renamed
fullscreen()
tosetFullscreen()
- (BREAK) renamed
isTouch()
toisTouchscreen()
- (BREAK) removed
layers()
in favor of parent game objects (see “layers” example) - (BREAK) removed
load()
event for components, useonLoad()
inadd()
event - (BREAK) removed
debug.objCount()
in favor ofgetAll().length
- added
debug.numFrames()
to get the current frame count
[2000.2.6] - 2022-01-27 (kaboom.js)
- fixed text always being wrapped if updated
- fixed text comp properties
letterSpacing
,charSpacing
,transform
,styles
not being exposed
v2000.2.5
- fixed updating
font
property on gameobj not updating the text font
v2000.2.4
- fixed
focus()
not properly exported - deprecated
focus()
in favor ofcanvas.focus()
due to name collision
v2000.2.3
- fixed
kaboom.d.ts
completely messed up
v2000.2.2
- fixed doc for
TextCompOpt#styles
andDrawTextOpt#styles
v2000.2.1
- fixed updates not running at all when
kaboom({ debug: false })
[2000.2.0] “Fancy Text Mode” 2022-01-23 (kaboom.js)
- added
formatText()
anddrawFormattedText()
- added
charSpacing
andlineSpacing
inTextCompOpt
andDrawTextOpt
- added optional
transitions
argument instate()
to define allowed transitions - added
StateComp#onStateTransition
to register event for specific transitions - added syntax to style a piece of text
"this is a [styled].wavy text"
andstyle
option inTextCompOpt
andDrawTextOpt
to define the styles withCharTransformFunc
- deprecated
dir()
in favor ofVec2.fromAngle()
- fixed
onTouchEnd()
fired ontouchmove
- added
outview()
component to control behavior when object leaves visible area - deprecated
cleanup(delay?: number)
in favor ofcleanup(opt?: CleanupOpt)
- deprecated
mouseWorldPos()
in favor oftoWorld(mousePos())
- deprecated
rng()
in favor ofnew RNG()
- added classes
Vec2
,Color
,Mat4
,Timer
,Quad
,RNG
,Line
,Rect
,Circle
- added deprecation warning
- fixed letterbox view mode
- allow non-stretch letterbox
- fixed mouse position malfunction in fullscreen, stretch and letterbox mode
[2000.1.8]
- fixed
Color#eq()
not giving correct result
v2000.1.7
- fixed not having export if installed from github repo with npm
- fixed event canceller returned by raw
onUpdate()
andonDraw()
crashing
v2000.1.6
- fixed debug widget scale
v2000.1.5
- fixed
enterState()
not passing args toonStateEnter()
callback
v2000.1.4
- fixed
state()
to not require registeringonStateUpdate()
before using any state
v2000.1.2
- fixed
onKeyRelease()
wrongfully check for key press instead of release
v2000.1.1
- fixed
StateComp#enterState()
not accepting any state
[2000.1.0] “Record Mode” - 2021-11-04 (kaboom.js)
- added
hsl2rgb()
for converting HSL color to kaboom RGB - added
record()
to start a screen recording - added F5 to screenshot and F6 to toggle record mode in debug mode
- added
DrawTextOpt#transform()
andTextCompOpt#transform()
for defining style and transformation for each character - added
state()
component for finite state machine - added support for multiple tags in
get()
andevery()
- added UI indicator for
debug.paused
anddebug.timeScale
- changed inspect mode UI style
- added color constants
WHITE
,BLACK
,BLUE
,GREEN
,RED
,MAGENTA
,CYAN
,YELLOW
- added new API style (
on
prefix for all event handler function,is
prefix for all boolean state getters)onLoad()
onUpdate()
onDraw()
onKeyPress()
onKeyPressRepeat()
onKeyDown()
onKeyRelease()
onMousePress()
onMouseDown()
onMouseRelease()
onMoueMove()
onTouchStart()
onTouchMove()
onTouchEnd()
onCollide()
onClick()
onHover()
isFocused()
isKeyDown()
isKeyPressed()
isKeyPressedRepeat()
isKeyDown()
isMouseDown()
isMousePressed()
isMouseReleased()
isMouseMoved()
isMouseMoved()
GameObj#onUpdate()
GameObj#onDraw()
AreaComp#onCollide()
AreaComp#onHover()
AreaComp#onClick()
BodyComp#onGround()
BodyComp#onFall()
BodyComp#onHeadbutt()
BodyComp#onDoubleJump()
BodyComp#isGrounded()
BodyComp#isFalling()
SpriteComp#onAnimEnd()
SpriteComp#onAnimStart()
HealthComp#onDeath()
HealthComp#onHurt()
HealthComp#onHeal()
AudioPlay#isStopped()
AudioPlay#isPaused()
[2000.0.0] “Burp Mode” - 2021-10-20 (kaboom.js)
- version jumped to v2000.0.0 (still semver, just big)
- added
burp()
for easy burping - added decent typescript / autocomplete support and jsdocs
- introducing new character “bean”
- added
loadBean()
to load"bean"
as a default sprite - changed default font to APL386, as
"apl386o"
(default outlined version) and"apl386"
- included font
kitchen sink as
"sinko"
(outlined version) and"sink"
(standard version with extended characters for text-mode games) - added
font
field inKaboomOpt
to set the default font - added
loadSpriteAtlas(src, entries)
to load sprite atlas - inspect mode now displays every comp’s state
- BREAK added continuous collision resolution which checks collision in
move()
if 2 objects are both “solid” (objects now won’t pass through other solid object at high speed or low framerate)
// before
add([sprite("player"), area()]);
add([sprite("rock"), solid()]);
keyDown("left", () => {
player.move(-120, 0);
});
player.action(() => {
player.resolve(); // or pushOutAll() in beta versions
});
// after
const player = add([sprite("player"), area(), solid()]);
// both should be solid
add([sprite("rock"), area(), solid()]);
keyDown("left", () => {
// this will handle collision resolution for you, if the other obj is also "solid"
player.move(-120, 0);
});
- added comp
opacity()
to set opacity - added comp
health()
to manage health related logic - added comp
move()
to manage projectile-like behavior - added comp
cleanup()
to auto destroy obj when it leaves screen - added comp
outline()
to draw a lil outline - added comp
timer()
to attach timers to a game obj - added comp
fixed()
to make a game obj unaffected by camera - added comp
stay()
to make a game obj stay after scene switch - added comp
lifespan()
to destroy game obj after certain amount of time - added comp
z()
to define draw order for objs on the same layer - added
weight
toBodyComp
andBodyCompOpt
to control the gravity multiplier - added
djump()
toBodyComp
for double jump - added
dir()
to calculate directional vector from angle - added constants
LEFT
,RIGHT
,UP
,DOWN
for unit directional vector - added
fullscreen()
to enable real fullscreen mode - BREAK separated color and opacity, removed
rgba()
in favor ofrgb
, use componentopacity()
to define opacity - BREAK changed color from 0-1 range to 0-255, angles from radians to degrees
// before
add([rotate(Math.PI / 2), color(0, 0.5, 1.0, 0.5)]);
// after
add([rotate(90), color(0, 127, 255), opacity(0.5)]);
global
anddebug
flag now are enabled by default, need to turn off manually if you don’t want- added input events
touchStart(id, pos)
,touchMove(id, pos)
,touchEnd(id, pos)
,mouseMove(pos)
- added
mouseDeltaPos()
- added
touchToMouse
to control if touch events should be translated to mouse events - added
mousePos()
now gets the screen mouse pos, usemouseWorldPos()
to get the mouse position affected by camera - added
anim
field inSpriteCompOpt
to play an anim on start - better type support for components
scene()
andstart()
(also removed in favor ofgo()
) are optional now, if you don’t need multiple scenes yet you can just go directly
kaboom();
// no mandatory scene() to start kabooming
add(...);
keyPress(...);
- BREAK
area()
is now explicit and not automatically added bysprite()
,rect()
, andtext()
, removed eachnoArea
orarea
config field - BREAK
area()
now takes anAreaCompOpt
, where you can define the area size, scale, and hover cursor
add([
sprite("bean"),
area(), // empty area will derive from sprite size
area({ scale: 0.5 }), // 0.5x the sprite size
area({ offset: vec2(0, 12), width: 4, height: 12 }), // more control over the collider region
]);
- BREAK renamed
isCollided()
toisColliding()
,isHovered()
toisHovering()
- BREAK removed
overlaps()
andisOverlapped()
and replaced withisColliding()
andcollides()
only checks doesn’t return true when 2 objects are just touching each other, useisTouching()
to check if they’re not colliding but just touching each other - added
isTouching()
to check if 2 objects are collided or just touching other - audio is now paused when you leave the tab
- audio is now paused on
debug.paused = true
- added local storage helper
getData(key, default?)
andsetData(key, data)
- added
loadShader(id, vert, frag, isUrl)
- added
shader()
comp for attaching custom shader to an obj - different layers do not prevent collisions now
- BREAK changed last argument of
loadFont()
toFontLoadOpt
- all event handlers like
keyPress()
,mouseClick()
,action()
,collides()
now returns a function to cancel that listener - added
require
on component definitions, making it possible to declare dependencies for components, e.g.
function alwaysRight() {
return {
// the id of this component
id: "alwaysRight",
// list of component ids that this requires
require: ["pos"],
update() {
// so you can use `move()` from pos() component with no worry
this.move(100, 0);
},
};
}
- BREAK overlapping component fields are not allowed, e.g. you can’t have a
custom comp that has a
collides
field if it already have aarea
component, since it already has that - BREAK changed
text(txt, size, conf)
totext(txt, conf)
withsize
as a field - added
obj.c(id)
for getting a specific comp’s state (by default all comps’ states are mounted to the obj byObject.defineProperty
)
// both works
obj.play("anim");
obj.c("sprite").play("anim");
- pedit, aseprite plugins are now included by default
- added
addKaboom()
for quick kaboom explosion load*()
now acceptsnull
as name and not load into assets manager, instead just return the resource data handle- BREAK renamed event
headbump
toheadbutt
- BREAK renamed event
grounded
toground
- added
width
,height
, andtiled
attrib toSpriteCompOpt
, for better control over sprite size and tiled sprite support - BREAK renamed
resolve()
topushOutAll()
onarea
comp - added
pushOut()
for pushing a single object out from another witharea
comp - fixed
"add"
event getting called twice for tagged objs - added
moveTo(dest: Vec2, speed?: number)
topos()
comp - added
keyPress()
(and all other key events) with no arg to check for any key - BREAK renamed
camShake()
toshake()
- added
flipX
andflipY
onsprite()
comp configuration, andflipX()
flipY()
methods - BREAK remove
flipX()
andflipY()
onscale()
comp - BREAK removed
start()
in favor ofgo()
- BREAK removed
changeSprite()
in favor ofuse(sprite("newsprite"))
- tags and components are converged, tags are just empty components now
- added
unuse()
to remove a component or tag - BREAK removed
rmTag()
in favor ofunuse()
- BREAK removed
camIgnore()
in favor offixed()
- BREAK renamed
makeRng()
torng()
- sprite animation now supports defining properties like loop and speed in load step and play step
loadSprite("hero", "hero.png", {
sliceX: 9,
anims: {
idle: { from: 0, to: 3, speed: 3, loop: true },
run: { from: 4, to: 7, speed: 10, loop: true },
hit: 8,
},
});
- BREAK changed
.play(anim, ifLoop)
undersprite()
to accept a dict of properties.play(anim, { loop: true, speed: 60, pingpong: true })
- BREAK now every symbol definition in
addLevel()
should be a function returning the component list, to ensure there’s no weird shared states
addLevel(["* *", "* *", "======"], {
"*": () => [sprite("wall"), area(), solid()],
"=": () => [sprite("floor"), area(), solid()],
});
- BREAK renamed
clearColor
tobackground
- added collision detection functions
testLineLine()
,testRectRect()
,testRectLine()
etc. - added drawing functions
drawSprite()
,drawRect()
,drawCircle()
,drawPolygon()
,drawEllipse()
,drawLine()
,drawLines()
- added transformation functions
pushTransform()
,popTransform()
,pushTranslate()
,pushRotate()
,pushScale()
- BREAK removed
areaWidth()
andareaHeight()
since they won’t make sense if the area shape is not rectangle, useworldArea()
if you need area data
const area = player.worldArea();
if (area.shape === "rect") {
const width = area.p2.x - area.p1.x;
const height = area.p2.y - area.p1.y;
}
v0.5.1
- added plugins npm package support e.g.
import asepritePlugin from "kaboom/plugins/aseprite"
[0.5.0] “Sticky Type” - 2021-05-11 (kaboom.js)
- platforms are now sticky
- moved to TypeScript
- improved graphics performance
- improved inspect drawing performance
- added on-screen log that catches all kinds of errors
- added
cursor()
- added
curPlatform()
bybody()
- added
falling()
bybody()
- added
changeSprite()
bysprite()
- added
duration()
andtime()
for the handle returned byplay()
- added optional
seek
field to the audio play confplay([conf])
- added
LoopHandle
returned byloop()
that has astop()
- added a default background (can be dismissed by setting
clearColor
) - fixed
sound.pause()
to work on firefox - fixed collisions not treating explicit default layer the same as implicit default layer
- fixed unable to play another anim in
onAnimEnd()
- fixed scene switches happen in the middle of a frame
- fixed
scale(0)
not working - fixed
mousePos()
not returning the camera affected pos with no layers - BREAK changed
dbg()
to plaindebug
object - BREAK moved
fps()
,objCount()
,stepFrame()
,log()
,error()
underdebug
- BREAK removed
debug.logTime
- BREAK changed component
debugInfo()
hook toinspect()
- BREAK removed
timer()
component - BREAK renamed
removeTag()
tormTag()
- BREAK changed
SpriteAnim
from[ from, to ]
to{ from: number, to: number }
- BREAK removed
onAnimPlay()
andonAnimEnd()
in favor of generic eventon("animEnd", (anim: string) => {})
- BREAK removed
obj.addTag()
in favor ofobj.use()
- BREAK merged
debug.hoverInfo
anddebug.showArea
intodebug.inspect
- BREAK removed
sound.resume()
in favor ofsound.play()
v0.4.1
- fixed
on("destroy")
handler getting called twice - fixed sprite
play()
not playing
[0.4.0] “Multiboom” - UNKNOWN (kaboom.js)
- BREAK removed
init()
andkaboom.global()
, in favor ofkaboom()
, also allows multiple kaboom games on one page
// replaces init(), and added a 'global' flag for previous kaboom.global()
kaboom({
global: true,
width: 480,
height: 480,
});
or not global
const k = kaboom();
k.scene();
k.start();
k.vec2();
- BREAK changed
clearColor
onkaboom(conf)
to accept a 4 number array instead ofrgba()
- added a plugin system, see the
multiboom
example andsrc/plugins
- BREAK removed support for
.kbmsprite
, supports newer version of.pedit
through pedit plugin - BREAK
loadAseprite()
and made it an external plugin underplugins/aseprite.js
- added
sceneData()
for custom scene data kv store - fixed
mouseClick
doesn’t work on mobile - disabled context menu on canvas
- prevented default behavior for ‘tab’ and function keys
- added
numFrames()
bysprite()
- added
screenshot()
that returns of a png base64 data url for a screenshot
[0.3.0] “King Dedede…Bug!” - UNKNOWN
- BREAK removed
pause()
andpaused()
in favor tokaboom.debug.paused
- BREAK removed
velY
,curPlatform
andmaxVel
fields bybody()
- BREAK changed
curAnim
bysprite()
to methodcurAnim()
- fixed
dt()
surge on page visibility change (#20) - pause audio when page is not visible
- added built in debug control with
init({ debug: true, })
`
: toggleshowLog
(default on withdebug: true
)f1
: toggleshowArea
f2
: togglehoverInfo
f8
: togglepaused
f7
: decreasetimeScale
f9
: increasetimeScale
f10
:stepFrame()
- added on screen logging with
log()
anderror()
- fixed
loadRoot()
sometimes doesn’t work in async tasks
[0.2.0] “Hear the Tremble” - UNKNOWN
- BREAK removed
aseSpriteSheet
conf field fromloadSprite(name, src, conf)
- added
pause()
,resume()
,stop()
,loop()
,unloop()
,volume()
,detune()
,speed()
methods to the handle returned byplay()
- added
camShake()
for built in camera shake - added
loadAseprite(name, imgSrc, jsonSrc)
- added area component generation for
text()
- added
noArea
to conf field ofsprite()
,rect()
andtext()
, allowing to disable auto area component generation - added a
quad
field to sprite comp creation configsprite(id, { quad: quad(0, 0, 0.5, 0.5) })
- fixed
resolve()
not working if the obj also hassolid
, so it does not check for itself (#8) mousePos()
accepts a layer argument, which returns the mouse position affected by camera transform if that layer is notcamIgnore()
-ed- fixed camera position getting calculated before completing every object’s update (#14)
- fixed some cases
on("grounded", f)
called multiple times when moving on a smooth platform - added
revery()
to iterate objects in reverse order - added
readd()
to re-add an object to the scene without triggering events - added
level.spawn()
[0.1.0] “Oh Hi Mark” -
- BREAK changed default origin point to
"topleft"
, so if you want object origin point to be at center you’ll need to manualorigin("center")
- BREAK integrated
kit/physics
andkit/level
to main lib - BREAK makes
collides()
only run on first collision, not run every frame during the same collision - BREAK
camPos()
by default focuses to center, socamPos(player.pos)
puts player in the center of the screen - BREAK renamed
kaboom.import()
tokaboom.global()
- added an arg field to
start(scene, ...)
to forward args to start scene - added
camScale()
,camRot()
andcamIgnore()
- added
obj.overlaps()
byarea()
, andoverlaps()
- added 3 ext fonts under
ext/fonts