SkillAgentSearch skills...

Kippy

Kippy 2D web game engine for JS

Install / Use

/learn @nguyenphuminh/Kippy
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<div align="center"> <img src="./assets/logo.png"/> </div>

Kippy is a 2D JS game engine written purely for fun and simplicity. It currently utilizes the Canvas 2D context for rendering and aims to have a small set of APIs viable for game dev, but do expect a lot of components to change in the future.

Usage

Install through npm:

npm install kippy

then import, for example:

import { Game, Scene, Entity } from "kippy";

or if you are on raw HTML5, you can pull from a cdn:

import { Game, Scene, Entity } from "https://unpkg.com/kippy";

Example

There is a Flappy Bird game in ./example for now. You can run it by cloning this repo, then install deps:

npm install

and build:

npm run build

and start Vite:

npx vite

Tutorial

Here is a vaguely-written tutorial for now:

Initialize game

First, prepare a canvas tag in your html file:

<canvas></canvas>

Then mount your game there:

import { Game } from "kippy";

const canvas = document.querySelector("canvas");
const game = new Game({
    canvas
});

// Start the game loop
game.start();

// You can also swap canvas if you want
// game.setCanvas(someOtherCanvas);

Create a scene

Here is how you can create a scene and load that scene into your game object:

import { Scene } from "kippy";

class Main extends Scene {
    // Runs when this scene gets loaded into a game
    init() {}
    // Runs on every frame, dt is the time between each frame
    update(dt) {}
    // Runs when another scene replaces this scene in a game
    exit() {}
}

// Create scene and load into game
const main = new Main();
game.setScene(main);

Create an entity

A scene can have multiple entities like players, mobs, obstacles, etc in it. This is how you can create an entity:

import { Entity } from "kippy";

const entity = new Entity({
    // These are all optional, and can also be set later

    // Graphics
    animator, // Entity's animator to be rendered, type Animator
    sprite, // Entity's sprite to be rendered, type Sprite
    // Position
    position, // Entity's position (centered), type Vector2
    rotation, // Entity's rotation in radians, type number
    // Physics
    body, // Entity's physical body, type EntityBody
    collider, // Entity's collider, type Collider
    // Effects
    glow
});

// Add it to a scene
scene.addEntity(entity);
// Remove it from a scene
scene.removeEntity(entity);

// These props contain movement info and you can mutate them to edit its position
entity.position; // Initialized from the "position" param above, Vector2(0, 0) if not specified
// You can mutate these directly:
entity.position.x;
entity.position.y;
entity.rotation; // Initialized from the "rotation" param above, 0 if not specified

Create a sprite

A sprite represents what an entity looks like (the "graphics part"), and you can create a sprite like this:

import { Sprite } from "kippy";

const sprite = new Sprite({
    texture, // Sprite's texture - HTMLImageElement, HTMLCanvasElement, OffscreenCanvas, ImageBitmap
    width, // Sprite's width, type number
    height // Sprite's height, type number
});

// Set sprite for an entity
entity.sprite = sprite;

Animation

First you create a sprite sheet that contains your frames:

import { SpriteSheet } from "kippy";

const spriteSheet = new SpriteSheet({
    texture, // Similar to sprite texture
    frameWidth, // Width of each frame, type number
    frameHeight, // Height of each frame, type number
    width, // Width when render, default is frameWidth
    height // Height when render, default is frameHeight
});

Then you create an animation object which defines the order of frame to play, fps, and whether to loop or not:

import { Animation } from "kippy";

const animation = new Animation({
    spriteSheet, // A SpriteSheet instance
    frames, // Order of frames, type number[]
    fps, // Frames per second, type number
    loop // Loop animation endlessly, type boolean
});

Then you create an animator, attach it to an entity, and then play an animation:

import { Animator } from "kippy";

const animator = new Animator({
    animations, // A Record<string, Animation> map that contains all animations
    default // The animation that will be played first, type string
});

// Attach it to an entity
entity.animator = animator

// Play an animation
entity.animator.play("animationName");

// You can also call a handler when animation ends
entity.animator.onEnd = function(name) {
    // Do something
}

Add controls

Game controls like mouse presses, key presses, touch, and cursor tracking (in the game canvas, not the web window) can be done by using the input handler from your game instance:

const input = game.input;

Then in a scene's update method, you can use these utilities to check for key presses:

// Keyboard
input.isKeyDown(/* Character/key here */); // true if key is held, false otherwise
input.isKeyPressed(/* Character/key here */); // true if key is pressed, false otherwise
input.isKeyReleased(/* Character/key here */); // true if key is released, false otherwise
// Mouse/touch
input.isPointerDown(/* 0 for left, 1 for right, 2 for touch */); // true if held, false otherwise
input.isPointerPressed(/* 0 for left, 1 for right, 2 for touch */); // true if pressed, false otherwise
input.isPointerReleased(/* 0 for left, 1 for right, 2 for touch */); // true if released, false otherwise
// Mouse/touch position
input.pointer; // Pointer's position vector
input.pointer.x; // Current X position of mouse/touch
input.pointer.y; // Current Y position of mouse/touch

Vectors

To work with positions and movements in Kippy, it is best to know about Vector2 first. Positions, velocities, forces, etc are all represented as vectors in Kippy. And here are how you can create a 2D vector and some vector math utilities that come along with it:

import { Vector2 } from "kippy";

const vect = new Vector2(/* x coordinate, number */, /*y coordinate, number */);

// Props
vect.x; // X coordinate
vect.y; // Y coordinate

// Utilities
vect.toString(); // Returns "Vector2(x, y)"
vect.add(otherVect); // Add another vector and return the result vector
vect.sub(otherVect); // Subtract another vector and return the result vector
vect.mul(otherVect); // Multiply with another vector and return the result vector
vect.div(otherVect); // Divide by another vector and return the result vector
vect.neg(); // Negate and return the result vector
vect.scale(scale); // Multiply with scale and return the result vector
vect.magnitude(); // Return the magnitude/length of vector
vect.magnitudeSquared(); // Return the squared magnitude/length of vector
vect.normalize(); // Return the normalized vector by magnitude
vect.dot(otherVect); // Return dot product with another vector
vect.cross(otherVect); // Return cross product with another vector
vect.project(otherVect); // Return projection on another vector
vect.min(otherVect); // Return a new vector with min coordinates
vect.max(otherVect); // Return a new vector with max coordinates
vect.floor(); // Floor rounding
vect.ceil(); // Ceil rounding
vect.round(); // Normal rounding
vect.distance(otherVect); // Return distance to another vector
vect.distanceSquared(otherVect); // Return squared distance to another vector
vect.copy(); // Return a copy (same coordinates, different reference)
vect.lerp(otherVect, scale); // Apply linear interpolation and return
vect.clamp(maxLength); // Clamp vector to have length below maxLength
vect.rotate(angle); // Return rotated vector by provided angle
vect.orthogonal(); // Return orthogonal vector of this vector
vect.angle(); // Return angle of vector.
vect.angleTo(otherVec); // Return angle between this and another vector
vect.reflect(otherVect); // Return reflection/bounce back vector
vect.equals(otherVect); // Check if two vectors are equal

// Useful constants
Vector2.ZERO; // Vector2(0, 0)
Vector2.ONE; // Vector2(1, 1);
Vector2.UP; // Vector2(0, -1);
Vector2.DOWN; // Vector2(0, 1);
Vector2.LEFT; // Vector2(-1, 0);
Vector2.RIGHT; // Vector2(1, 0);

Physics

For movements, currently you can create a RigidBody:

import { RigidBody } from "kippy";

// Create a rigid body
const rigidBody = new RigidBody({
    velocity, // Entity's velocity vector, type Vector2
    rotationVelocity, // Entity's angular/rotation velocity, type number
    mass, // Entity's mass, type number
    inertia, // Entity's inertia, type number
    force, // Entity's force vector, type Vector2
    torque, // Entity's torque/rotational force, type number
    restitution // Entity's restitution for collision bounce back, type number
});

// Attach body to an entity
entity.body = rigidBody;

// And you can mutate these props to update movement every frame
entity.body.velocity; // Set with the matching parameter above, default is Vector2(0, 0)
entity.body.rotationVelocity; // Set with the matching parameter above, default is 0
entity.body.mass; // Set with the matching parameter above, default is 1
entity.body.inertia; // Set with the matching parameter above, default is 1
// Note that forces are reset after every frame
entity.body.force; // Set with the matching parameter above, default is Vector2(0, 0)
entity.body.torque; // Set with the matching parameter above, default is 0
entity.body.restitution; // Set with the matching parameter above, default is 0

For collisions, you can create a CircleCollider for now:

import { CircleCollider } from "kippy";

const collider = new CircleCollider({
    radius, // Circle collider's radius, 

Related Skills

View on GitHub
GitHub Stars4
CategoryDevelopment
Updated2d ago
Forks0

Languages

TypeScript

Security Score

90/100

Audited on Apr 2, 2026

No findings