- Minimal setup: only a canvas and a game class required
- High-performance rendering via Worker + SharedArrayBuffer
- Simple, stateless rendering model for predictable behavior
pip install @tetsup/web2dimport { GameApp } from '@tetsup/web2d';
const app = new GameApp(canvas, new TestGame(), {
maxObjects: 10,
rectSize: { width: 320, height: 240 },
keyAssignment,
assignPad,
});new GameApp(
canvas: HTMLCanvasElement,
game: Game,
options?: {
maxObjects?: number;
rectSize?: { width: number; height: number };
keyAssignment?: any;
assignPad?: any;
}
)canvas→ Target<canvas>element for renderinggame→ Instance of a class implementing game logicoptions(optional)maxObjects→ Maximum number of renderable objectsrectSize→ Virtual screen size (internal resolution)keyAssignment→ Keyboard input mappingassignPad→ Gamepad input configuration
You only need to implement the following two methods:
class MyGame {
async onInit(renderer) {}
async onTick(input, clock, renderer) {}
}onInit→ Called once at initializationonTick→ Called every frame
Start the application with:
app.start();You can also control the game using the following methods:
app.start(); // Start game loop and input handling
app.pause(); // Pause
app.advance(n); // Advance simulation by n milliseconds
app.destroy(); // Fully stop and release resources-
start()
- Starts the game loop and input handling
-
pause()
- Stops input handling
- Pauses the game loop
-
advance(delta)
- Advances the game state by
deltamilliseconds - Useful for debugging and deterministic simulation
- Advances the game state by
-
destroy()
- Stops all processes
- Terminates the Worker
- Should be called when disposing the app
The renderer is provided as an argument to lifecycle methods.
renderer.registerImage({ imageId, imageData });
renderer.render([{ pos, imageId }]);Registers an image for rendering.
renderer.registerImage({
imageId: 'player',
imageData: bitmap,
});imageId: string- Identifier for the image
imageData: ImageBitmap- Transferred to Worker (ownership moves)
ImageBitmapcannot be reused after transfer- Re-register with a new bitmap to update
Submits objects to be rendered for the current frame.
renderer.render([
{
pos: { x: 100, y: 200 },
imageId: 'player',
},
]);pos: { x: number, y: number }- Position in pixels
imageId: string- Must be registered beforehand
- Rendering is stateless per frame
- All visible objects must be sent every frame
- Internally optimized using SharedArrayBuffer
Full example: