Getting Started With Primary Primary Games: What It Actually Is
Primary Primary Games is a lightweight 2D game prototyping framework built on top of HTML5 canvas and vanilla JavaScript. It strips away the bloat most beginners run into with bigger engines and lets you wire together game loops, sprites, and basic physics without installing a dependency tree that weighs a hundred megabytes. The core idea is simple: you define entities, you run a loop, you render frames. That's it. Most tutorials skip that part and jump straight into asset pipelines, which is why people get confused early on. The framework organizes everything around an entity-component system, though it's far less rigid than what you'd find in something like Unity or Godot. You create an entity by calling a constructor, attach components to it for behavior and rendering, then push it into the world manager. The engine handles the update cycle and rendering queue. There's no scene graph complexity, no nested nodes, no hierarchy debugging sessions that eat your afternoon. You pass in a config object, the framework creates the canvas, sets up requestAnimationFrame, and you start calling addEntity() from there. I spent about three days wrestling with this when I first picked it up because the documentation assumes you already understand component lifecycle ordering. Specifically, the update order matters more than the docs imply. If you register a physics component after a collision handler component, the collision won't fire correctly during the same frame. I learned that the hard way when a platformer prototype kept clipping through floors at low frame rates. The workaround was straightforward: always register components in a consistent order every time, and make sure physics comes before rendering and input comes before physics in the registration sequence. That alone fixed 90% of the weird edge-case behavior I was seeing.
Installing and Setting Up the Project
You can grab the latest build directly from the official repository. Clone or download the archive, then point your HTML file at the compiled script. No build step required unless you're modifying the source itself. The minimal setup looks like this: include the script, initialize the world with a canvas size and a fixed timestep, register your components, and start running. The framework ships with a few built-in components out of the box — sprite renderer, circle collider, AABB collider, and a basic velocity-based movement system. If you need something beyond that, you write a custom component using the same interface they all share. One thing that catches people off guard is that Primary Primary Games does not bundle an asset loader by default. Textures, audio, anything you want loaded before the game starts has to be handled in your own code. I wrote a small preload wrapper that uses Promises to wait on all assets, then calls start() on the world once everything resolves. Without that, you'll get blank sprites and missing sounds on first load every single time because the render loop starts before your images are done downloading. It's a fifteen-line addition but it saves a lot of head-scratching.
Common Pitfalls and Counter-Intuitive Details
Most beginners assume the fixed timestep means the game runs at a constant speed regardless of hardware. That's only true if your frame rendering stays within the timestep budget. On slower machines, the update loop can fall behind and start accumulating a frame backlog, which makes the game stutter in a very noticeable way. The fix is not to increase the timestep — that actually makes it worse — but to cap the maximum number of updates per frame and let the render rate vary independently. There's a config flag for this called maxSubSteps, and setting it to 8 instead of the default 32 will smooth things out on weaker hardware considerably. Another thing that's not obvious: the collision system uses continuous collision detection only for circle colliders by default. AABB colliders use discrete detection, which means fast-moving objects can tunnel through thin walls if your timestep is too loose. I ran into this with a bullet projectile moving at high velocity. It passed straight through a one-pixel-wide barrier because the distance per frame exceeded the barrier's thickness. Switching that one entity to use a circle collider for the physics body fixed it, even though the visual sprite remained a rectangle. The collider shape and the render shape don't have to match, and using a circle for fast projectiles is a common trick that doesn't show in the docs at all.
Get the Full Details

Writing Your First Entity
Let me walk through what creating a basic player entity actually looks like in practice. You initialize the world, register your components, create the entity, attach the sprite renderer with a texture path, attach the AABB collider with dimensions, attach the velocity movement component, and register input listeners. That's roughly ten lines of actual game logic before you even add any gameplay mechanics. The framework is deliberately sparse, which is both its strength and its weakness. You get total control, but you also have to wire everything yourself. There's no visual editor, no drag-and-drop inspector, no debug overlay you can toggle on without writing code. Speaking of debugging, the framework includes a minimal debug mode that overlays position, velocity, and collider bounds on every entity. It's enabled by passing debug: true in the world config. I recommend keeping this on during development because seeing where the collision boxes actually sit relative to the sprites reveals more problems than anything else. Half the bugs I encounter in new projects are just collider bounds being slightly misaligned with the art, and the debug view makes that immediately visible.
Performance Considerations You Shouldn't Ignore
Primary Primary Games is fast for small to medium projects, but it is not designed for large-scale games with thousands of on-screen entities. The collision system is O(n²) in the worst case, and there's no spatial partitioning built in. If you're working on something with more than a few dozen moving objects that can collide, you'll want to implement your own broad-phase culling or switch to a different framework. I've seen people push this engine past its limits by accident — the API is simple enough that you don't realize the performance wall is coming until your framerate drops to single digits on a mid-range laptop. That happened to me with a top-down shooter that had too many projectiles active simultaneously. The fix was to pool the projectile entities and reuse them instead of creating and destroying them, which reduced GC pressure and brought the frame rate back to acceptable levels. The entity pooling feature exists but is undocumented beyond a single line in the changelog. You call createPool() on the world with a factory function, and then acquire and release entities from the pool instead of creating new ones. It sounds trivial but it makes a measurable difference in projects that spawn and destroy objects frequently. Memory allocation in JavaScript is not free, and the garbage collector will pause your frame every so often if you're allocating heavily. Pooling avoids that entirely.
When Primary Primary Games Is the Right Tool
It's useful for rapid prototyping, game jams, educational projects, and small published games where you don't need a full engine. It's not useful if you need multiplayer networking out of the box, if you're building a 3D game, if you need a visual level editor, or if your project will grow beyond a few hundred entities. For those cases, looking at Godot or Defold would save you migration pain later. But if you just want to get something moving on screen quickly and understand exactly how every piece fits together without opaque abstractions, Primary Primary Games does that job competently. It doesn't hide the machinery from you, which means you learn more by using it than by using something that abstracts everything away. The learning curve is steep in the beginning because there's so little hand-holding, but once you understand the component lifecycle and the update order, most of the friction disappears. The hardest part is knowing what to look for when something goes wrong, since the error messages are deliberately minimal. I keep a personal checklist now for debugging: verify component registration order, check collider shapes against sprite dimensions, confirm assets are loaded before start(), and make sure the timestep isn't too loose for the movement speeds in the game. Following that checklist reduces debugging time from hours to minutes in most cases.
