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.
[unreleased]
Added
-
Added
KAPLAYOpt.types
,kaplayTypes()
andOpt
to config specific TypeScript Advanced Features (TAF) - @lajbelkaplay({ types: kaplayTypes< // Opt<> is optional but recommended to get autocomplete Opt<{ scenes: {}; // define scenes and arguments strictScenes: true; // you can only use defined scenes }> >(), });
-
Added
TypesOpt.scenes
to type scenes and parameters - @lajbelconst k = kaplay({ types: kaplayTypes< Opt<{ scenes: { "game": [gamemode: "normal" | "hard"]; "gameOver": [score: number, highScore: number]; }; }> >(), }); // If you trigger autocomplete it shows "game" or "gameOver" k.scene("game", (gamemode) => { // gamemode is now type "normal" | "hard" // @ts-expect-error Argument of type 'string' is not assignable // to parameter of type 'number'. k.go("gameOver", "10", 10); // });
The methods that support this are:
-
Added
TypesOpt.strictScenes
to make usable scenes just the ones defined - @lajbelconst k = kaplay({ types: kaplayTypes< Opt<{ scenes: { "game": [gamemode: "normal" | "hard"]; "gameOver": [score: number, highScore: number]; }; strictScenes: true; }> >(), }); // @ts-expect-error Argument of type '"hi"' is not assignable to // parameter of type '"game" | "gameOver"'. k.scene("hi", () => {});
-
Added named animations - @mflerackers
By giving a name to an animation, you can define more than one animation
const anim = obj.animation.get("idle"); anim.animate("pos", [0, 5, 0], { relative: true });
-
Added
screenshotToBlob()
to get a screenshot as aBlob
- @dragoncoder047 -
Added
getButtons()
to get the input binding buttons definition - @lajbel -
Added
RuleSystem
for enemy AI - @mflerackers -
Added
DecisionTree
for enemy AI - @mflerackers -
Added constraint components for distance, translation, rotation, scale and transform constraints - @mflerackers
-
Added skew to Mat23, transformation stack, RenderProps, GameObjRaw as well as a component - @mflerackers
Changed
- (!)
KAPLAYCtx
doesn’t use generics anymore. Now,KAPLAYCtxT
uses them - @lajbel - Now,
kaplay
will returnKAPLAYCtx
orKAPLAYCtxT
depending if it’s using Advanced TypeScript Features or not - @lajbel loadShader()
now also checks for link errors as well as compile errors and reports them rather than just silently trying to use a borked shader - @dragoncoder047- The debug
record()
function now records with sound enabled like it should - @dragoncoder047 - Now
KAPLAYOpt.spriteAtlasPadding
is set to2
by default - @lajbel - Transformation and drawing is split now, so the transform can be modified before drawing - @mflerackers
[4000.0.0-alpha.21] - 2025-08-07
Added
-
Added
GameObjRaw.serialize()
for serializing the game object and its components. - @mflerackers, @lajbelconst bean = add([sprite("prefab")]); const beanSerialized = bean.serialize();
-
Added
createPrefab()
for serializing an object and register it (or not) as a prefab from a Game Object. - @mflerackers, @lajbelconst beanObj = add([sprite("bean")]); // Serialize game object and register it as a prefab asset createPrefab("bean", beanObj); addPrefab("bean"); // Just get serialized data const serializedBean = createPrefab(beanObj); addPrefab(beanObj);
-
Added
addPrefab()
for creating an object previously serialized - @mflerackers, @lajbelloadPrefab("bean", "/bean.kaprefab"); addPrefab("bean");
-
Added new scene methods
pushScene()
andpopScene()
, for stack behaviour in scenes - @itzKiwiSky -
Added
throwError()
for throwing custom errors to the blue screen, even errors KAPLAY can’t handle. - @lajbel -
Added
insertionSort()
- @dragoncoder047 -
Added a mapping for PS5 (DualSense) gamepads, so now you can bind actions to the touchpad press (only works in Chrome for some reason) - @dragoncoder047
Changed
- Now
GameObjRaw.exists()
work for nested objects - Now moving mouse changes the value of
getLastInputDevice()
- @amyspark-ng - (!) Renamed
KAPLAYOpt.tagsAsComponents
toKAPLAYOpt.tagComponentIds
- @lajbel
Fixed
- Fixed shader error messages - @dragoncoder047
- Fixed compatibility issues when calculating font height with missing TextMetrics props - @imaginarny
[4000.0.0-alpha.20] - 2025-06-15
Added
- Added
loadSpriteFromFont()
for loading a bitmap font from a loaded sprite. - @dragoncoder047
Changed
- Improved various doc entries. - Many contributors
Fixed
- Fixed
AreaComp#onClick()
attaching events to app, instead of object, so event wasn’t being paused withobj.paused
- @lajbel - Fixed all touch events having a bad transformation - @lajbel
- Fixed sprite scaling not working properly with
KAPLAYOpt.letterbox
- @mflerackers - Fixed “add” event running twice in
addLevel()
tiles - @lajbel - Fixed blend component having a wrong ID - @lajbel
Removed
- (!)
loadPedit()
was removed - @lajbel
[4000.0.0-alpha.19] - 2025-05-16
This version changelog covers versions 4000.0.0-alpha.0 through 4000.0.0-alpha.19, as we didn’t have a concise changelog strategy before.
Added
-
Added
fakeMouse()
to create a fake mouse cursor - @lajbelconst myCursor = add([fakeMouse(), sprite("kat"), pos(100, 100)]); myCursor.press(); // trigger onClick events if the mouse is over myCursor.release(); myCursor.moveBy(vec2(100, 200)); // move as your wish
-
Added
system()
to replace internal events or create new - @mflerackerssystem("collision", () => { // system code }, [SystemPhase.AfterFixedUpdate, SystemPhase.AfterUpdate]),
-
Added
ellipse()
component - @mflerackers -
Added circle and (rotated) ellipse collision shapes - @mflerackers
-
Added
clipLineToRect()
- @mflerackers -
Added
obj.setParent()
to change the parent of a game object - @mflerackers -
Added restitution and friction to physics - @mflerackers
-
All game objects have methods
onTag()
andonUntag()
for watching tag changes - @mflerackers -
Added
SystemPhase
enum to identify different lifecycle events in the game loop that systems can hook into - @mflerackers -
Added Blend mode is selectable to change how sprites are composited on top of each other - @mflerackers
-
Added Picture API to cache drawing of selected objects - @mflerackers
-
Added
drawCanvas()
- @mflerackers -
Added
video()
component to embed a video file into the game - @mflerackers -
Added
level()
component and parent argument toaddLevel()
- @KeSuave -
Allow the
text()
component to change the font and apply shaders per-character - @dragoncoder047 -
Allow characters in text to be scaled and have the text flow around it with
stretchInPlace: false
- @dragoncoder047 -
Expose the formatted text parsing functions to allow manipulation of formatted text - @dragoncoder047
-
Now you can use the frames of a sprite in an atlas also as a font - @dragoncoder047
-
More errors raised during object creation are caught and cause the blue crash screen - @lajbel
-
The blue crash screen will no longer fail to draw if the error message contains brackets - @dragoncoder047
-
Now you can use the global option
inspectOnlyActive: false
to prevent paused objects from showing in the debug inspect view, this is useful if you are swapping out objects for different views - @dragoncoder047 -
The
OffScreenComp
now has an optionoffscreenDistance
to change the distance at which an object is considered off-screen - @dragoncoder047 -
Now you can cherry-pick specific frames of a sprite sheet by using the
frames
list, instead of being limited to consecutive framesstart
andend
- @dragoncoder047 -
wave()
can now go back and forth between any value that is able to be used withlerp()
- @dragoncoder047, @mflerackers -
The
TextInputComp
has more events:focus
,blur
,input
, andchange
, to better interact with the text input state - @dragoncoder047 -
Areas no longer struggle with parents whose transform inst’t up-to-date - @mflerackers
-
Exported step and smoothstep - @mflerackers
-
Small circles and arcs use now less points than larger ones - @mflerackers
-
Added pushMatrix, storeMatrix and loadIdentity to the stack functions - @mflerackers
-
Typed
StateComp
- @amyspark-ng -
Added bias to line drawing, which controls the offset from the center of the line - @mflerackers
-
Added
SpriteAnimPlayOpt.preventRestart
to allowSpriteComp.play()
to be called from anonUpdate()
and not reset the animation to frame 0 - @dragoncoder047
Changed
- (!) - Now
z()
is global instead of relative - @mflerackers - (!) Layers now work globally, no longer only between siblings - @mflerackers
- (!): Changed default behavior to
kaplay({ tagsAsComponents: false })
- The physics engine creates less garbage - @mflerackers
- Tag-based events are slightly faster - @dragoncoder047
- Moved camera to the shader - @mflerackers
- Replaced the Separating Axis Theorem (SAT) collision detection module with the
Gilbert–Johnson–Keerthi
(
GJK
) algorithm, which is faster - @mflerackers - Now if you pass a nullish value to
.use()
it throws an error - Improved TypeScript in game objects - @amyspark-ng, @lajbel, @KeSuave
- Added/updated JSDoc comments to some members - @ErikGXDev, @dragoncoder047
- The
textInput
component’sisFocused
property is now a one-hot lockout, setting it to true (focused) will clear focus from all the other text inputs - @dragoncoder047 - Changed the API of
HealthComp
- @amyspark-ng - CapsLock now affects
TextInputComp
- @amyspark-ng
Fixed
GameObjRaw.exists()
now correctly returns false if the parent was destroyed but obj wasn’t - @dragoncoder047Vec2.dot()
now actually does the Correct Calculation™ - @andrenanninga- Fixed
debug.timeScale
not affectingdt()
scale - @lajbel - Fixed
wait()
’sTimerComp.onEnd()
being waiting for twice the duration - @dragoncoder047 - Fixed non-focused
TextInputComp
backspace - @KeSuave - Fixed 9slice sprites behaving wrong when using
Anchor
- @mflerackers - Fixed rendering glitches with outlines on circles - @mflerackers
- Fixed
setCursorLocked(true)
throwing error if the browser is using the old non-Promise-based API return value - @imaginarny - Fixed
PatrolComp
not going to last waypoint - @nojaf - Fixed various TypeScript types - @amyspark-ng, @lajbel, @KeSuave
Removed
- (!)
make()
was sent to doom - @lajbel