# Technical Documentation: KilledByAPixel/LittleJS

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/KilledByAPixel/LittleJS)

### Overview (`README.md`)

# LittleJS - The Tiny Fast JavaScript Game Engine

<div align='center' markdown='1'>
    


[![NPM Package][npm]][npm-url]
[![Build Size][build-size]][build-size-url]
[![NPM Downloads][npm-downloads]][npmtrends-url]
[![DeepScan][deepscan]][deepscan-url]
[![MIT License][license]][license-url]
[![Discord][discord]][discord-url]

</div>

## 🚂 All Aboard!

LittleJS is a fast, lightweight, and fully open source HTML5 game engine designed for simplicity and performance.
Its small footprint is packed with a comprehensive feature set including 2D and 3D rendering, physics, particles, sound, and input handling.
The code is very clean and well documented with many examples to get you started quickly.

### 🚀 [Join the LittleJS Game Jam](https://itch.io/jam/littlejs-jam)

*The Third Annual LittleJS Game Jam will take place from Oct 2 to Nov 2! Unleash your creativity and develop amazing games using the LittleJS game engine.*

<div align='center' markdown='1'>

## [Examples](https://killedbyapixel.github.io/LittleJS/examples) | [Arcade](https://killedbyapixel.github.io/LittleJSArcade) | [Docs](https://killedbyapixel.github.io/LittleJS/docs) | [Reference](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) | [FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) | [Trailer](https://youtu.be/V3ik8SKJF4g) | [Discord](https://discord.gg/zb7hcGkyZe)  | [AI](https://github.com/KilledByAPixel/LittleJS-AI)

</div>





## LittleJS Features

### ✨ Graphics

- Blazing fast WebGL2 + Canvas2D hybrid rendering system
- Apply [Shadertoy](https://www.shadertoy.com) style shaders for post-processing effects, or on any object or draw
- 2D lights with soft shadows, tinted glass and emissive objects, a sun with long shadows, and spotlight cones and gels
- Robust particle effect system with a library of ready made effects and an [effect design tool](https://killedbyapixel.github.io/LittleJS/examples/particles/)
- Parallax background layers that repeat across a level of any size
- Load sprites and animations into texture sheets at runtime, or import [TexturePacker](https://www.codeandweb.com/texturepacker) and [Aseprite](https://www.aseprite.org) atlases

### 🧊 LittleJS 3D

- Built-in 3D renderer that shares the canvas with your 2D game
- 3D objects with the same physics, children and timers as 2D
- Shape builders, extruded sprites and text, and OBJ and glTF model loading
- Height map terrain and voxel maps with collision and raycasts
- 3D levels and prefabs, built in the 3D level editor and loaded with one call
- Shadow maps, colored lights, spotlights, lens flares, specular, emissive glow and fog
- Reflections of a sky box or the scene itself, from mirror sharp to rough
- Particles, trails, billboards and instanced drawing
- Orbit, chase and first person cameras with mouse picking
- Custom shaders on any object
- Optional [Three.js](https://threejs.org) plugin as an alternative renderer

### 🔊 Audio

- Sound and music with mp3, ogg, or wave files
- Use [ZzFX](https://killedbyapixel.github.io/ZzFX/) sound generator to play sounds without asset files
- Spatial audio with stereo panning
- Audio effects plugin with filter, reverb, delay, distortion and compressor

### 🎮 Input

- Comprehensive input handling for mouse, keyboard, gamepad, and touch
- Customizable on screen gamepad designed for mobile devices
- Pinch to zoom on touch screens, read the same way as the mouse wheel

### 💥 Physics

- Robust arcade physics system with collision handling
- Fast tilemap collision and raycasting, with one-way platforms that turn with their tiles
- Swept bullet collision, so small fast objects never pass through a wall
- Object collision that stays fast with thousands of objects
- Full Box2D integration for realistic physics using [Box2D v2.3.1 wasm](https://github.com/kripken/box2d.js)
- Grid-based A* pathfinding plugin with optional path smoothing

### 🚀 Flexibility

- Compatible with all modern web browsers and mobile devices
- Full TypeScript and Module support with example projects for both
- [Vite](https://vite.dev) starter template for instant dev server with hot reload
- Great for size coding competitions like [Js13kGames](https://js13kgames.com/)
- Open Source and [MIT licensed](https://github.com/KilledByAPixel/LittleJS/blob/main/LICENSE)

### 🛠️ Developer Tools

- Live example browser with code editor
- Built-in 2D and 3D level editors that edit your game while it runs, with undo, autosave and prefabs
- Make the editors your own with your game's own object types, keys, buttons and tools, see the [editor guide](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md)
- 2D levels load and save as [Tiled](https://github.com/mapeditor/tiled) JSON, so Tiled can edit them too
- UI system with buttons, sliders, text input and nine-slice skins
- Tween system with easing curves, and a scene system for titles, menus and game states
- Debug overlay and primitive rendering system
- Medals, leaderboards and cloud saves on [Newgrounds](https://www.newgrounds.com/) and [Wavedash](https://wavedash.com/)
- Node.js build system

### 🤖 AI Friendly

- The entire API is small and well documented so LLMs can produce high quality results
- [LittleJS AI Tools](https://github.com/KilledByAPixel/LittleJS-AI) - Templates, examples, and prompts tuned for AI + LittleJS workflows
- [LittleJS GPT](https://chatgpt.com/g/g-67c7c080b5bc81919736bc8815836be6-littlejs-game-maker) - Build LittleJS games right inside ChatGPT

## How To Use LittleJS

To get started download the latest release from GitHub, the engine's builds and source as npm has them (the examples are in the repository), or install via npm: 

```
npm install littlejsengine
```

or use `degit` for an empty Vite template

```
npx degit KilledByAPixel/LittleJS/examples/vite-starter my-game
cd my-game
npm install
npm run dev
```

The examples are only in the repository: clone it, or use Download ZIP on its GitHub page; the npm package and the release zip hold the engine alone. A page that loads images or modules needs a local web server, as browsers block them from a file on disk: serve the repository's root, for example with `npx http-server`, then open `http://localhost:8080/examples/starter/`, the place to start. The [FAQ](FAQ.md#do-i-need-a-local-server-to-run-littlejs-games-and-how-do-i-set-one-up) has more.

Here is a minimal Hello World example game, with the script path pointing at the engine file from the download or npm package; it loads nothing, so it runs straight from the file.

```html
<!DOCTYPE html>
<script src="node_modules/littlejsengine/dist/littlejs.js"></script>
<script>
function gameInit() {}
function gameUpdate() {}
function gameUpdatePost() {}
function gameRender() {}
function gameRenderPost() { drawTextScreen('Hello World!', mainCanvasSize.scale(.5), 80); }
engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost);
</script>
```

## Tutorials

- [Making Awesome Games With LittleJS](https://youtu.be/_dXKU0WgAj8) - A short talk about LittleJS with some tips on how to use it
- [Tutorial: Breakout](https://github.com/KilledByAPixel/LittleJS/tree/main/examples/breakoutTutorial) - Learn how to make a simple game from scratch
- [Tutorial: Make a ski game](https://eoinmcgrath.com/little-ski/tutorial.html) - A tutorial by eoinmcg that shows how to make a pixel art style game
- [LittleJS Quick Reference Sheet](https://github.com/KilledByAPixel/LittleJS/blob/main/REFERENCE.md) - The whole API in one file, made to be read by people and by AI coding tools
- [Making Your Own Level Editor](https://github.com/KilledByAPixel/LittleJS/blob/main/EDITOR.md) - How to turn the built in 2D and 3D level editors into an editor for your own game
- [LittleJS FAQ](https://github.com/KilledByAPixel/LittleJS/blob/main/FAQ.md) - Answers to common questions about LittleJS
- [Changelog](https://github.com/KilledByAPixel/LittleJS/blob/main/CHANGELOG.md) - What changed in each release
- [JS13k Branch](https://github.com/KilledByAPixel/LittleJS/tree/js13k) - A special branch for size coding events that builds to a 7KB zip

## Examples

LittleJS comes with several demos both for learning and using as starter projects to create new games.

- [Example Browser](https://killedbyapixel.github.io/LittleJS/examples/) - Live example browser with all examples and editable source
- [LittleJS Arcade](https://killedbyapixel.github.io/LittleJSArcade/) - Over 50 example games you can use as starter projects
- [Short Examples](https://killedbyapixel.github.io/LittleJS/examples/) - 100+ single-file demos showing off individual engine features
- [Breakout](https://killedbyapixel.github.io/LittleJS/examples/breakout/) - Block breaking game with post-processing effects
- [Puzzle Game](https://killedbyapixel.github.io/LittleJS/examples/puzzle/) - Match 3 puzzle game with HD rendering and high score tracking
- [Platformer](https://killedbyapixel.github.io/LittleJS/examples/platformer/) - Platformer/shooter demo that loads level data
- [Box2D Demo](https://killedbyapixel.github.io/LittleJS/examples/box2d/) - Box2D plugin demonstration and testbed
- [3D Example](https://killedbyapixel.github.io/LittleJS/examples/3d/) - The 3D plugin in one scene: terrain, shadows, lights, sprites, particles and bloom
- [3D Racing Game](https://killedbyapixel.github.io/LittleJS/examples/?example=3D%20Racing%20Game) - Built-in 3D plugin: terrain, shadows and a chase camera in one short file
- [Three.js Platformer](https://killedbyapixel.github.io/LittleJS/examples/threejs/) - 3D platformer with LittleJS gameplay and Three.js rendering
- [Particle System Designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) - Particle system editor and visualizer

## Builds

| File | Mode | Module | Use case |
|------|------|--------|----------|
| [littlejs.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.js) | Debug | No | Debug mode with asserts |
| [littlejs.release.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.release.js) | Release | No | Optimized for release |
| [littlejs.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.min.js) | Release | No | Optimized for release and minified |
| [littlejs.esm.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.js) | Debug | ESM | Debug mode with asserts |
| [littlejs.esm.min.js](https://github.com/KilledByAPixel/LittleJS/blob/main/dist/littlejs.esm.min.js) | Release | ESM | Optimized for release and minified |

Every build includes the plugins. littlejs.min.js is about 135 KB gzipped, and the 3D plugins are a large part of that. A bundler like Vite leaves out the plugins a game does not use, so a small 2D game comes to about 26 KB gzipped, and a lit 3D scene to about 47 KB.

## Games Made With LittleJS

Here are a few of the many amazing games created with LittleJS...

- [Space Huggers](https://www.newgrounds.com/portal/view/819609) - Roguelike platformer shoot-em-up game with procedural levels. by [KilledByAPixel](https://frankforce.com/)
- [Black Cat Squadron](https://js13kgames.com/games/black-cat-squadron) - One button shooter based on a WW2 Navy squadron. JS13k 5th place! by [repsej](https://github.com/repsej)
- [L1ttl3 Paws](https://github.com/KilledByAPixel/JS13K2025) - Cat glider with procedural art and levels for JS13K! by [KilledByAPixel](https://frankforce.com/)
- [KleptoKitty](https://js13kgames.com/games/kleptokitty) - Cat themed heist puzzle. JS13K 22nd place. by [eoinmcg](https://eoinmcg.itch.io/)
- [The Way of the Dodo](https://js13kgames.com/2024/games/the-way-of-the-dodo) - Single button platformer. JS13k 5th place! by [repsej](https://github.com/repsej)
- [Undergrowth](https://undergrowth.squidband.uk/) - An interactive music videogame for the band Squid. by [KilledByAPixel](https://frankforce.com/)
- [204Snake!](https://www.newgrounds.com/portal/view/960100) - A puzzle game that combines 2048 with snake. LittleJS Jam 1st place! by [Sodoj](https://sodoj.itch.io/) and [Shai-P](https://shai-p.itch.io/)
- [GATOR](https://www.newgrounds.com/portal/view/960757) - Retro platformer shooter game where you rescue animals. LittleJS Jam 2nd place! by [eoinmcg](https://eoinmcg.itch.io/)
- [A Hedgehog's Search](https://willsm1111.itch.io/a-hedgehogs-search) - Adventure game starring a hedgehog. LittleJS Jam 3rd place! by [willsm1111](https://willsm1111.itch.io/)
- [Wendol Village](https://js13kgames.com/2024/games/wendol-village) - Warcraft inspired RTS game. by [sanojian](https://github.com/sanojian)
- [Dead Again](https://js13kgames.com/entries/dead-again) - Top down survival horror. by [sanojian & repsej](https://github.com/sanojian/js13k_2022)
- [Isletopia](https://store.steampowered.com/app/1861260/Isletopia) - Relaxing strategy game of greenifying barren islands. by [Gamex Studio](https://x.com/gamesgamex)
- [Tetrimals](https://nixn.itch.io/tetrimals) - A puzzle game mixing Tetris with animals. by [nixn](https://nixn.itch.io/)
- [Bug&Bee](https://itch.io/jam/littlejs-game-jam-2025/results) - Low fi shoot em up with co-op gameplay. LittleJS Jam 1st place! by [eoinmcg](https://eoinmcg.itch.io/)
- [Little Platformer](https://psemo.itch.io/little-platformer) - Platformer with many mechanics. LittleJS Jam 2nd place! by [PSEMO](https://psemo.itch.io/), [Solita666](https://itch.io/profile/solita666), [GabrielRG](https://gabrielrg.itch.io/), [Nate](https://natesassoon.itch.io/)
- [Alien Escape Pinball](https://focaccai.itch.io/alien-pinball) - Pinball game with physics and aliens. by [Focaccai](https://www.focaccai.com/)
- [LittleJS Jam 2024 Results](https://itch.io/jam/littlejs-jam-2024/results) - All the games from the first LittleJS Game Jam.
- [LittleJS Jam 2025 Results](https://itch.io/jam/littlejs-game-jam-2025/results) - All the games from the second LittleJS Game Jam.



*A sample of games built with LittleJS.*



[npm]: https://img.shields.io/npm/v/littlejsengine
[npm-url]: https://www.npmjs.com/package/littlejsengine
[build-size]: https://img.shields.io/bundlephobia/minzip/littlejsengine
[build-size-url]: https://bundlephobia.com/result?p=littlejsengine
[npm-downloads]: https://img.shields.io/npm/dw/littlejsengine
[npmtrends-url]: https://www.npmtrends.com/littlejsengine
[deepscan]: https://deepscan.io/api/teams/22950/projects/26229/branches/831487/badge/grade.svg
[deepscan-url]: https://deepscan.io/dashboard#view=project&tid=22950&pid=26229&bid=831487
[discord]: https://img.shields.io/discord/939926111469568050
[discord-url]: https://discord.gg/zb7hcGkyZe
[license]: https://img.shields.io/github/license/KilledByAPixel/LittleJS
[license-url]: https://github.com/KilledByAPixel/LittleJS/blob/main/LICENSE

---

### Overview (`bench/README.md`)

# LittleJS benchmarks

Pages that put LittleJS and other engines through the same scene, so a change to the engine can be measured and
anyone can check the numbers on their own hardware. The other engines load from a CDN, nothing here is part of
the engine.

## Running

Serve the repo and open a page, or the whole set:

```bash
node bench/serve.mjs          # then open http://localhost:8765/bench/all.html
```

`all.html` runs every page in turn at 1280 by 720, twice each, and prints one line per result with a copy
button. `?only=particles` runs one set, `?quick=1` runs each page once. Or open a single page; each takes
`?n=` or `?s=` for its size and `?w=1280&h=720` to fix the canvas, and says what else it takes at the top
of its source.

Headless, with `playwright-core` installed somewhere node can find it (the repo has no dependency on it):

```bash
node bench/run.mjs particles              # a set at a few sizes
node bench/run.mjs dynamic 128 256 -- aa=0
node bench/profile.mjs "bench/particles.html?n=20000&aa=0&w=320&h=180"
```

Headless Chrome renders with SwiftShader, a software GPU, so those numbers compare JS and driver overhead and
say nothing about real hardware. `profile.mjs` prints where the JS time goes.

## Reading the numbers

- **frame** is the time between frames. In a browser it can never go below the display refresh, so 16.7 ms
  means "at least 60 fps", not "16.7 ms of work".
- **gpu** is the time the card spent on the frame's commands, from a timer query. It is only meaningful when the
  frame is at the refresh rate: when the CPU is the bottleneck the GPU idles between commands and that idle
  counts, so a CPU bound page shows a large gpu number that is really CPU time.
- **js** or **update** and **render** are CPU phases measured in the page.
- **updates** is how many engine updates each rendered frame got on a LittleJS page. The fixed timestep runs
  gameUpdate up to three times a frame to catch up below 60 fps, so a page that reads 3 is doing three times the
  update work per frame that it would at 60 fps; compare object counts where it still reads 1.
- Run a page twice. The spread between two runs of the same page is the noise floor; a difference smaller than
  that means nothing.

## The pages

| page | scene | against |
|---|---|---|
| cubes | n spinning lit cubes with a shadow map; `?objects=0` draws from arrays, `?instanced=1` keeps them in an InstancedMesh3D | three.js InstancedMesh, `?instanced=0` a Mesh each |
| particles | n soft dot particles from one emitter | three.js Points with a size and color shader |
| sprites | n camera facing sprites, sorted | three.js Sprite |
| dynamic | a grid whose points move every frame; `?dynamic=0` without mesh.dynamicDraw | PlaneGeometry with needsUpdate |
| bigmesh | one terrain of 2 s² triangles with a shadow map, plus build and upload times | PlaneGeometry |
| sprites2d | n tiles bouncing around the screen, the bunnymark; `?objects=1` as EngineObjects | PixiJS Sprite, `?particles=1` ParticleContainer; Phaser Image, `?blitter=1` Blitter (WebGL1, so no gpu time) |

`benchLittle.js` and `benchOther.js` hold the shared timing: 60 warm up frames, then 300 timed, and
`window.benchResult` when done. The LittleJS pages do their per frame work in a pre render hook rather than
gameUpdate, because the fixed timestep runs gameUpdate several times a frame below 60 fps, which would count the
work several times over; the other pages step their simulations the same way.

---

### Overview (`examples/breakoutTutorial/README.md`)

# LittleJS Breakout Tutorial

For this tutorial we will start with the empty project in the LittleJS examples folder. This is a blank template to start a new project.

The empty project has only 3 files: one for html, one for js, and one image. The index.html and image files will not need to be changed for this example. The 
[game.js](https://github.com/KilledByAPixel/LittleJS/blob/main/examples/empty/game.js) file contains a stubbed out project with all the JavaScript code and is the only file we will be working with today.

Get the [LittleJS repository from GitHub](https://github.com/KilledByAPixel/LittleJS), by cloning it or with Download ZIP; the examples are not in the npm package. The page needs a local web server: serve the repository's root, for example with `npx http-server`, and open `http://localhost:8080/examples/empty/`. A copy of the empty folder somewhere else changes its `import '../../dist/littlejs.esm.js'` to where the engine is.

In this tutorial we will make a breakout style game with a player controllable paddle, a ball that bounces, and bricks that break when hit. This is a great introduction to LittleJS and takes only around 30 minutes to complete.

[The tutorial is also available on YouTube!](https://youtu.be/tSwDx-NWTXE?si=bkjMa8-7AN2Wg5MO)

## [You can play the result of this tutorial here.](https://killedbyapixel.github.io/LittleJS/examples/breakoutTutorial/)



## Create the Bricks

The first step is to make a 2D grid of brick objects in gameInit. As a placeholder we will create an EngineObject for each cell in the grid and set it to have a random color.

```javascript
// create bricks
for (let x=0; x<=20; x++)
for (let y=0; y<=20; y++)
{
    const brick = new LJS.EngineObject(vec2(x,y)); // create a brick
    brick.color = LJS.randColor(); // give brick a random color
}
```

That will make a square of 20×20 engine objects, we can adjust it as we go. It also assigns the color property of each brick to a random color.



It is completely off center and may not look like much yet, but it's a start!

## Improve the Bricks

Let's make the bricks more rectangular by passing vec2(2,1) to the size parameter of Engine Object. We will need to adjust the loop to add 2 for each x iteration. Also we can use a Vector2 to describe the size of the level.

```javascript
// create bricks
const levelSize = vec2(20, 20);
for (let x=0; x<=levelSize.x; x+=2)
for (let y=0; y<=levelSize.y; y+=1)
{
    const brick = new LJS.EngineObject(vec2(x,y), vec2(2,1)); // create a brick
    brick.color = LJS.randColor(); // give brick a random color
}
```

## Move the Camera

Let's move the camera to the center of our level by setting the cameraPos variable to half the level size.
You can also change the camera zoom by using cameraScale which controls the number of pixels for each world space unit.
For this example the camera will just remain stationary, but in other types of games it is very useful!

```javascript
LJS.setCameraPos(levelSize.scale(.5)); // center camera in level
```

We'll also start with a blank slate by commenting out the default “Hello World!” text in gameRenderPost.

```javascript
// LJS.drawTextScreen('Hello World!', LJS.mainCanvasSize.scale(.5), 80);
```



It is getting closer! The camera is now centered and blocks are rectangular.

## Modify the Level Size

For this example we will use a fixed size canvas. This will let the drawing canvas always be the same resolution, even if the window size changes. Black space is added on the sides to compensate. It is a great option for any game that uses a single screen like this.

To enable it we will set canvasFixedSize in gameInit to use 720p resolution.

```javascript
LJS.setCanvasFixedSize(vec2(1280, 720)); // use a 720p fixed size canvas
```

Before we tweak the level size, let's add this bit of code to gameRender to show the size of the level. This will cause some rects to be drawn each frame before the engine objects. To create color objects we pass hue, saturation and lightness values between 0 and 1 to hsl, a saturation of 0 gives a gray.

```javascript
LJS.drawRect(LJS.cameraPos, vec2(100), hsl(0,0,.5)); // draw background
LJS.drawRect(LJS.cameraPos, levelSize, hsl(0,0,.1)); // draw level boundary
```

We also need to make levelSize a global by moving it to the top so it can be accessed from other functions.

```javascript
const levelSize = vec2(38, 20); // size of play area
```

Now we can see the boundaries of our level and tweak the size to fill the canvas. I found that a level size of vec2(38, 20) works well here.

We can also adjust the for loop where the bricks are created to make them only fill the top middle part of the level.

```javascript
for (let x=2;  x<=levelSize.x-2; x+=2)
for (let y=12; y<=levelSize.y-2; y+=1)
{
    const brick = new LJS.EngineObject(vec2(x,y), vec2(2,1)); // create a brick
    brick.color = LJS.randColor(); // give brick a random color
}
```



Now that looks almost like a breakout game!

## Create the Player Paddle

For the player's paddle, let's create a new class of object that extends the built in EngineObject. This will allow us to control movement with the mouse. In this Paddle class we will just add some new code to the update function which is automatically called each frame by the engine.

```javascript
class Paddle extends LJS.EngineObject
{
    update()
    {
        this.pos.x = LJS.mousePos.x; // move paddle to mouse
    }
}
```

Then we just need to create the paddle in gameInit.

```javascript
new Paddle; // create player's paddle
```

There is now a square paddle that moves along the bottom of the screen.

Let's make the paddle wider and move it up a smidge by adding a constructor to the Paddle class.

```javascript
constructor()
{
    super(vec2(0,1), vec2(6,.5)); // set object position and size
}
```



Now there is a player controllable paddle that moves along the bottom of the screen.

You can also add this code to the paddle update that will keep the paddle from following the mouse offscreen, though it is not required.

```javascript
// clamp paddle to level size
this.pos.x = LJS.clamp(this.pos.x, this.size.x/2, levelSize.x - this.size.x/2);
```

## Create the Ball
The final missing piece is of course that ball that moves around and bounces off of stuff. We will leverage the built in physics solver to handle all the ball's physics and collision math.

We can create a Ball class the same way we created the paddle. In this case we will also apply some velocity to ball so it starts moving right away.

```javascript
class Ball extends LJS.EngineObject 
{
    constructor(pos)
    {
        super(pos); // set object position

        this.velocity = vec2(-.1, -.1); // give ball some movement
    }
}
```

We will keep track of the ball in a global variable, so add it near the top of the file with the other globals.

```javascript
let ball; // keep track of ball object
```

Then we just need to create the ball in gameInit, passing in the camera position for its location.

```javascript
{
    // create a ball
    ball = new Ball(LJS.cameraPos);
}
```

## Make the Ball Collide

You may have noticed that the ball goes right through the paddle and bricks. To enable collision we just need to call setCollision on the ball and the paddle by adding a call in both of their constructors.

```javascript
this.setCollision(); // make object collide
```

Now the ball collides but unfortunately also pushes the paddle away, not quite what we want. To prevent the paddle from being moved by physics we will make it use static physics by setting its mass to 0 in the paddle constructor.

```javascript
this.mass = 0; // make object have static physics
```

Getting closer, the paddle is not pushed away but the ball doesn't bounce either. To make it bounce, we need to set the ball's restitution which controls how much it will bounce.

```javascript
this.restitution = 1; // make object bounce
```



It works! The ball now bounces off the paddle, still not the walls or blocks yet though.

Before we continue, let's make the ball a bit smaller by changing the super call in its constructor.

```javascript
super(pos, vec2(.5)); // set object position and size
```

## Make the Ball Bounce Off Walls

Next, let's make the ball bounce when it hits the top or sides of the screen. To do this, we will make a Wall object class that works similar to the paddle but without an update function.

```javascript
class Wall extends LJS.EngineObject
{
    constructor(pos, size)
    {
        super(pos, size); // set object position and size

        this.setCollision(); // make object collide
        this.mass = 0; // make object have static physics
    }
}
```

We can create walls on the sides and top by adding a few more lines of code to the gameInit function.

```javascript
// create walls
new Wall(vec2(-.5,levelSize.y/2),            vec2(1,100)) // left
new Wall(vec2(levelSize.x+.5,levelSize.y/2), vec2(1,100)) // right
new Wall(vec2(levelSize.x/2,levelSize.y+.5), vec2(100,1)) // top
```



Now we have white walls around the outside that block the ball. These walls should be invisible so we will set their color to be transparent by adding another line to the Wall constructor.

```javascript
this.color = hsl(0,0,0,0); // make object invisible
```

## Debug Display

This is a good time to try opening up the debug info by pressing escape. This feature will allow for a selection of debug overlays while also showing all game objects with more info displayed for the object closest to the mouse. It can be really useful when trying to diagnose bugs and understand what is going on.



As you can see, the wall objects are still present even though they are now invisible.

## Respawn the Ball

We should respawn the ball when it goes below the screen so players can keep playing.

We can remove the old code that was creating a new ball in gameInit, and instead create the ball in gameUpdate, only when it is needed.

```javascript
// if there is no ball or ball is below level
if (!ball || ball.pos.y < -1)
{
    // destroy old ball
    if (ball)
        ball.destroy();

    // create a ball
    ball = new Ball(LJS.cameraPos);
}
```

Don't forget to destroy the old ball before creating the new one! Though it doesn't really matter for this simple example, it would cause the old balls to continue existing while being updated and rendered. That could really slow things in bigger games with thousands of objects.

## Break the Bricks

Still, the ball doesn't collide with the bricks much less breaks them and it wouldn't be breakout without that. So we need to make the brick collide with the ball, just like the walls, so let's start with Brick class that is the same as Wall.

```javascript
class Brick extends LJS.EngineObject
{
    constructor(pos, size)
    {
        super(pos, size);

        this.setCollision(); // make object collide
        this.mass = 0; // make object have static physics
    }
}
```

And we will just change the for loop in gameInit to use the Brick class.

```javascript
const brick = new Brick(vec2(x,y), vec2(2,1)); // create a brick
```

Now the ball will bounce off the bricks, but we want it to break the bricks. To do this we can override the brick's collideWithObject function which is called by the engine when the ball hits it. Instead of the default collide behavior, we just destroy the brick.

```javascript
collideWithObject(o)              
{
    this.destroy(); // destroy block when hit
}
```

But wait! This will cause the ball to careen through the bricks without bouncing. Maybe fun for a special powerup, but not our goal here. This function should return a Boolean value to indicate if the collision needs to be resolved, if it returns false then the ball will not bounce. So the answer is to just add another line of code to the collideWithObject function that returns a truthy value indicating that the collision should occur.

```javascript
return true; // allow object to collide
```



Success, we have breakout! All the core components are here though there are a few more changes we can make that will greatly increase the playability.

## Track the Player's Score

We can easily add a score tracker to the game by making a global score variable called score.

```javascript
let score = 0; // start score at 0
```

Then increment it in the Brick.collideWithObject function.

```javascript
++score; // award a point for each brick broke
```

And change that drawTextScreen code we had commented out in gameRenderPost to display the score. We can adjust the position and size of the text to fit at the top of the screen.

```javascript
LJS.drawTextScreen('Score ' + score, vec2(LJS.mainCanvasSize.x/2, 70), 50); // show score
```



## Add Sound Effects

So far the game is completely silent. Let's add sounds using ZzFX. This is a tiny sound effect generator that works in conjunction with LittleJS and can be used on its own too.

We will start with the ball bounce sound. [You can use the official ZzFX sound designer to create your own sound.](https://killedbyapixel.github.io/ZzFX/) I recommend using the Blip preset for this one.

To make a sound effect with this system we will create a global object for each sound.

```javascript
const sound_bounce = new LJS.Sound([,,1e3,,.03,.02,1,2,,,940,.03,,,,,.2,.6,,.06], 0);
```

You can use the sound I chose or copy the code for your own sound from ZzFX. There is a checkbox for LittleJS style sounds to make exporting a little easier.

To play the sound we will override collideWithObject for the Ball class. Also remember we must return true for the collision to occur.

```javascript
collideWithObject(o)              
{
    sound_bounce.play(); // play bounce sound
    return true; // allow object to collide
}
```
Let's also make a brick break sound. You can use the ZzFX sound designer again to create your own sound, for this one try the Hit preset.

Create a global object for this sound the same way we did for the bounce sound. You can replace it with your own generated sound or use mine.

```javascript
const sound_break = new LJS.Sound([,,90,,.01,.03,4,,,,,,,9,50,.2,,.2,.01], 0);
```

Then in the Brick's collideWithObject function just add some code to play that sound.

```javascript
sound_break.play(); // play brick break sound
```

Now you should hear sound as the ball bounces around and breaks bricks! Of course it is easy to swap out these sounds with other ones, feel free to experiment.

## Add Click To Start Interaction

Let's improve the gameplay by letting the player click to start, instead of creating the ball right away. This will also ensure that the player has clicked which is requirement for audio to play in most browsers.

We can also add a special sound that plays on startup. Try making an interesting start from the ZzFX sound designer, maybe using the Powerup preset.

```javascript
const sound_start = new LJS.Sound([,0,500,,.04,.3,1,2,,,570,.02,.02,,,,.04]);
```

We can modify the gameUpdate to wait for player input from the mouse and play the sound when the ball is created.

```javascript
if (ball && ball.pos.y < -1) // if ball is below level
{
    // destroy old ball
    ball.destroy();
    ball = 0;
}
if (!ball && LJS.mouseWasPressed(0)) // if there is no ball and left mouse is pressed
{
    ball = new Ball(LJS.cameraPos); // create the ball
    sound_start.play(); // play start sound
}
```

## Add Particle Effects

Let's add some effects when the bricks break. You can use the [LittleJS particle system designer](https://killedbyapixel.github.io/LittleJS/examples/particles/) to create an explosion effect.

This will be a one shot type of effect, not a continuous emitter so change emitTime to something small like .1 for this example. Now before you play with it too much, let's test it by pasting in the code it generated into the Brick's collideWithObject function. Tick **Expanded** in the code panel first, then press Copy: expanded, the designer writes the whole emitter, `const emitter = new ParticleEmitter(` with one setting a line, which is what is used here. Left unticked it writes a one line `particleEffect('Name', vec2())`, which plays an effect from the built-in library by its name, and an effect you changed only once your own library is loaded.

Make sure you replace the first parameter, vec2(), with this.pos so the effect appears wherever the brick is, otherwise it will spawn at the world origin.

The designer writes code for a plain script where every engine name is global, so in this module project put `LJS.` in front of each engine name it uses that the file does not take from `LJS` at the top, like `ParticleEmitter`, `particleEffect`, `tile`, `PI` or `particleEffectShapeTile`; `vec2` and `hsl` are already taken. Here the tile is left `undefined` for plain untextured particles, and the settings are written on one line to save room.

```javascript
// create explosion effect
new LJS.ParticleEmitter(this.pos, 0, 0, 0.1, 100, 3.14, undefined, hsl(0, 0, 1, 1), hsl(0, 0, 1, 1), hsl(0, 0, 1, 0), hsl(0, 0, 1, 0), 0.5, 0.1, 1, 0.1, 0.05, 1, 1, 0, 3.14, 0.1, 0.2, false, false, true);
```

Now you should see this simple particle effect play wherever a brick breaks. You can continue tweaking the parameters to make your own effect or use the one I made which also uses this.color to change the particle's color so it matches the brick.

```javascript
// create explosion effect
const color = this.color;
new LJS.ParticleEmitter(
    this.pos, 0,             // pos, angle
    this.size, .1, 200, 3.14,// emitSize, emitTime, rate, cone
    undefined,               // tileInfo
    color, color,                       // colorStartA, colorStartB
    color.scale(1,0), color.scale(1,0), // colorEndA, colorEndB
    .2, .5, 1, .1, .1,  // time, sizeStart, sizeEnd, speed, angleSpeed
    .99, .95, .4, 3.14, // damp, angleDamp, gravity, cone
    .1, .5, false, true // fade, randomness, collide, additive
);
```



## Improve the Gameplay

Last but certainly not least, let's make a few small improvements to the gameplay. It would help to give the player some more control of where the ball goes when it hits the paddle. We can do this by adding some code to the ball's collideWithObject function.

This code will use the rotate function to modify the bounce angle based on the distance from the center of the paddle.

We will also slightly increase the speed of the ball each time it hits the paddle to make the difficulty of the game ramp up over time.

```javascript
collideWithObject(o)              
{
    // prevent colliding with paddle if moving upwards
    if (o == paddle && this.velocity.y > 0)
        return false;

    sound_bounce.play(); // play bounce sound

    if (o == paddle)
    {
        // control bounce angle when ball collides with paddle
        const deltaX = o.pos.x - this.pos.x;
        this.velocity = this.velocity.rotate(.3 * deltaX);
        
        // make sure ball is moving upwards with a minimum speed
        this.velocity.y = LJS.max(-this.velocity.y, .2);
        
        // prevent default collision code
        return false;
    }

    return true; // allow object to collide
}
```

Also we will need to make the paddle a global object like the ball.

```javascript
let paddle; // keep track of player's paddle
```

And assign that paddle object when it is created in gameInit.

```javascript
paddle = new Paddle; // create player's paddle
```

While we are working in the ball's collideWithObject function, let's also make it speed up a little bit each time it bounces. Put this right after the check that stops it colliding with the paddle while it moves up, before the bounce sound, since the next step plays that sound with this speed.

```javascript
// speed up the ball
const speed = LJS.min(1.04*this.velocity.length(), .5);
this.velocity = this.velocity.normalize(speed);
```

## Improve the Sound

Let's make the sound a bit more interesting by using positional audio. This lets the volume and panning be adjusted based on the sound's on screen location. To enable this, just pass a position to the sound's play function.

```javascript
sound_break.play(this.pos); // play brick break sound
```

For the ball bounce sound, let's also tweak the pitch by how fast the ball is moving. For the sound play function, the second parameter takes a scalar for volume and the third parameter takes a scalar for pitch.

```javascript
sound_bounce.play(this.pos, 1, speed*2); // play bounce sound with pitch scaled by speed
```

With every step in, the ball's collideWithObject looks like this, as in [the tutorial's finished game.js](https://github.com/KilledByAPixel/LittleJS/blob/main/examples/breakoutTutorial/game.js):

```javascript
collideWithObject(o)
{
    // prevent colliding with paddle if moving upwards
    if (o == paddle && this.velocity.y > 0)
        return false;

    // speed up
    const speed = LJS.min(1.04*this.velocity.length(), .5);
    this.velocity = this.velocity.normalize(speed);

    // play bounce sound with pitch scaled by speed
    sound_bounce.play(this.pos, 1, speed*2);

    if (o == paddle)
    {
        // control bounce angle when ball collides with paddle
        const deltaX = o.pos.x - this.pos.x;
        this.velocity = this.velocity.rotate(.3 * deltaX);

        // make sure ball is moving upwards with a minimum speed
        this.velocity.y = LJS.max(-this.velocity.y, .2);

        // prevent default collision code
        return false;
    }

    return true; // allow object to collide
}
```

## Congratulations on Completing the Breakout Tutorial

Now you know the basics of how to use the LittleJS engine! [The final result with all the code from this tutorial is playable here.](https://killedbyapixel.github.io/LittleJS/examples/breakoutTutorial/)

If you need a little help completing the tutorial, [join us on the LittleJS discord](https://discord.gg/zb7hcGkyZe). 

Feel free to continue building on this tutorial to make a more interesting breakout game. What kind of ideas would you like to include?

You can also check out [the breakout example game](https://killedbyapixel.github.io/LittleJS/examples/breakout/) which extends this tutorial to show textured objects, post processing, and image fonts.



There are several other example games you can use as a starting point for your own creations, or use a new blank project like we did for this example. What will you build with LittleJS? 🚂

---

### Overview (`examples/vite-starter/README.md`)

# LittleJS + Vite

This template provides a minimal setup to get LittleJS working in Vite.

## Use as a template

Spin up a fresh project from this template with [degit](https://github.com/Rich-Harris/degit):

```
npx degit KilledByAPixel/LittleJS/examples/vite-starter my-game
cd my-game
npm install
npm run dev
```

Requires Node 22.12+, what the LittleJS package and its tools are tested on.

## Getting started

```
npm install
npm run dev
```

## Vite commands

```
npm run dev       # dev server, the page reloads on save
npm run build     # build to dist/
npm run preview   # preview the production build
```

See the [Vite docs](https://vite.dev) for more.

## Assets

Files in `public/` are served from the site root in dev and copied as-is to `dist/` on build. The tilesheet lives there, which is why `engineInit(..., ['tiles.png'])` works in both dev and the built output.

For assets you want Vite to hash and bundle (the usual case for large projects), import them from `src/` instead:

```js
import tilesURL from './tiles.png';
```

## Deploying

The included `vite.config.js` sets `base: './'`, which makes the built site work from any subdirectory — including GitHub Pages project sites and itch.io uploads. The `public/.nojekyll` file ships in the build so GitHub Pages won't ignore Vite's underscore-prefixed chunk files.

To deploy:

```
npm run build
```

then upload the contents of `dist/` (or zip them for itch.io).

## LittleJS

[Read the LittleJS docs to learn more](https://github.com/KilledByAPixel/LittleJS).

---

--- METRICS ---
- Files Extracted: 4
- Estimated Token Budget: ~10600 tokens
- Canonical Reference: https://codewiki.google/github.com/KilledByAPixel/LittleJS
