Counter-Strike on PSP: OpenStrike runs at 60fps with JavaScript

Counter-Strike on a PSP sounds like the sort of thing you’d expect from an old concept video. Something clever, a little unstable, and probably running at ten frames per second. OpenStrike is very different. It’s a single-player tactical shooter built for Sony’s handheld, and it runs on original PSP hardware at a reported 60 frames per second. The game takes clear inspiration from classic Counter-Strike, with familiar maps, weapons, bots, recoil, ammunition management and round-based action. The surprising part isn’t just that it works. A large part of the game’s logic and its complete on-screen interface run in TypeScript and JavaScript. Underneath that, Rust handles the demanding work, while a compact graphics engine deals with the PSP’s ageing hardware. That mix sounds strange at first. The PSP was never designed for modern web-style development, reactive interfaces or scripting-heavy game engines. It has a 333MHz MIPS processor, limited memory and a fixed-function graphics chip from a very different era. Yet OpenStrike makes the combination work.

Counter-Strike on a PSP sounds like the sort of thing you’d expect from an old concept video. Something clever, a little unstable, and probably running at ten frames per second. OpenStrike is very different. It’s a single-player tactical shooter built for Sony’s handheld, and it runs on original PSP hardware at a reported 60 frames per second. The game takes clear inspiration from classic Counter-Strike, with familiar maps, weapons, bots, recoil, ammunition management and round-based action. The surprising part isn’t just that it works. A large part of the game’s logic and its complete on-screen interface run in TypeScript and JavaScript. Underneath that, Rust handles the demanding work, while a compact graphics engine deals with the PSP’s ageing hardware. That mix sounds strange at first. The PSP was never designed for modern web-style development, reactive interfaces or scripting-heavy game engines. It has a 333MHz MIPS processor, limited memory and a fixed-function graphics chip from a very different era. Yet OpenStrike makes the combination work.

It isn’t a direct Counter-Strike port

OpenStrike doesn’t try to disguise itself as an official version of Counter-Strike. It’s better understood as a new game and engine built around the same kind of tactical shooting. The structure feels familiar. You enter a map, deal with armed enemies, manage your weapon and ammunition, and move through elimination-style rounds. There’s a crosshair, a score display, health information and the other visual elements you’d expect from this kind of shooter.

What it doesn’t include is the full online ecosystem of the PC game. This is mainly a single-player experience built around bots. That makes sense on the PSP, where keeping the scope under control is just as important as technical ambition.

The project also avoids bundling copyrighted maps. Instead, it supports GoldSrc-era BSP level data, which lets the engine work with compatible maps without presenting itself as an authorised release. That distinction matters. OpenStrike isn’t trying to replace Counter-Strike. It’s showing how a similar style of game can be rebuilt for one of Sony’s most limited 3D platforms.

Rust does the heavy lifting

The game splits its workload between native code and JavaScript. Rust handles the systems that need to be fast and predictable. That includes movement, collision detection, bots, weapons, bullets, simulation and 3D rendering. These jobs can’t afford delays.

At 60 frames per second, the PSP has around 16.7 milliseconds to process everything needed for one frame. That includes player input, enemy behaviour, game logic, interface updates and graphics. Miss that window too often and the game starts to feel sluggish.

Rust keeps those critical systems close to the hardware. It gives the developers tight control over memory, timing and data layout, which matters far more on a PSP than it would on a modern PC. The rendering side uses Pocket3D. On desktop systems, the engine can rely on modern graphics technology through wgpu. On PSP, it talks directly to Sony’s sceGu graphics system.

That allows the same basic game to run across two very different platforms. The desktop version gets modern hardware and higher resolutions. The PSP version works with a 480 by 272 screen, a small amount of system memory and just 2MB of video memory. That’s a serious gap. OpenStrike bridges it by keeping the core game portable while swapping out the lower-level graphics work underneath.

JavaScript runs the game rules

Here’s where the project gets especially interesting. OpenStrike uses an embedded QuickJS engine to run its TypeScript and JavaScript code. This script layer controls higher-level behaviour, including round flow, scoring, weapon settings and other game-specific rules. That means developers can change how the game behaves without rebuilding every low-level part of the engine. It also runs the complete HUD.

Health, ammunition, crosshair behaviour, enemy counts, damage indicators, score information and round status all come from a component-based interface written with Solid and JSX-style code. No browser is involved. There’s no webpage hiding underneath the game, and the PSP isn’t loading a traditional HTML interface. PocketJS provides a small bridge between the JavaScript code and the native renderer. The interface behaves like a modern reactive application, but it draws through the game engine instead of a browser.

Each frame, the Rust side sends game-state information and events to JavaScript. The scripts update the rules and interface, then return a small set of commands. The boundary stays narrow on purpose. Rust produces the facts. JavaScript makes higher-level decisions. That keeps the system flexible without letting the script layer slow down the parts that need exact timing.

One game bundle, two platforms

OpenStrike’s portability is one of its strongest ideas. The same JavaScript bundle can run on desktop and PSP. Developers don’t need one set of rules for PC and another for the handheld. Change a weapon value in TypeScript, and that change can work on both. Adjust the HUD, round logic or bot settings, and the same game package carries those edits across different hardware targets.

That’s a much cleaner setup than building the PSP version as a completely separate project. The game itself sits above the engine. The native code acts as the host. This approach also means the developers use the same scripting system for the main game that other people could use for modifications. There’s no hidden internal API reserved only for the original project. What you see is what the game itself uses. That’s an unusual level of consistency for a small technical project.

Old maps need modern preparation

OpenStrike supports classic BSP map data from the GoldSrc era. BSP stands for binary space partitioning. The format divides a level into sections so the engine can work out which areas might be visible from the player’s current position. That saves work. If you’re standing in one room, the PSP doesn’t need to process every wall and corridor on the other side of the map. The visibility data helps it ignore geometry that can’t be seen.

Still, loading old PC map data directly on the PSP would waste time and memory. So the project prepares the files before they reach the handheld. A desktop build tool reads the BSP map and its texture archives, then converts everything into a format designed for the PSP. It arranges geometry in a hardware-friendly layout, compresses textures, prepares mipmaps, converts position data and bakes lighting into vertex colours. The PSP gets a finished package.

It doesn’t need to perform complicated conversion work after launch. It doesn’t need to unpack large temporary files or rebuild textures while the player waits. That leaves more processing power for movement, enemies and gunplay. It’s a practical decision. Do the expensive work once on a modern computer, then give the PSP exactly what it needs.

Hitting 60 frames per second

The reported 60fps performance didn’t happen by accident. OpenStrike’s developers measured how much time each part of the game used. During testing on real hardware, average frame times reportedly stayed between around 6.8 and 8.4 milliseconds. The worst measured frame reached 9.7 milliseconds. That leaves room under the 16.7-millisecond target. JavaScript caused problems early on.

The first version of the HUD copied the entire game state into a single reactive value every frame. Every interface component then acted as though something had changed, even when most values stayed the same. That was expensive. The HUD alone pushed JavaScript beyond the available frame budget. The fix sounds simple, but it made a major difference. The developers split the state into smaller signals and added equality checks. Now a HUD element only updates when its own value changes.

Health doesn’t redraw because ammunition changed. The score doesn’t refresh because the crosshair moved. That reduced the JavaScript cost to around 2.2 milliseconds per frame. The rest of the engine follows the same rule: don’t process work that isn’t needed.

Visibility data limits geometry. Mipmaps simplify distant textures. Compact texture formats reduce memory use. Lighting gets baked ahead of time. No single trick makes the game fast. The performance comes from dozens of careful choices.

Memory is the real enemy

The PSP-1000 has 32MB of RAM, but games can’t freely use all of it. OpenStrike reportedly uses around 6.2MB for the executable, engine, QuickJS runtime, JavaScript bundle and prepared map data. Its working memory, including the JavaScript heap, engine state and temporary frame data, peaks at about 4.4MB. That leaves useful breathing room. Video memory is much tighter.

The PSP only has 2MB of VRAM. Framebuffers and depth storage take up around 1.4MB, which doesn’t leave much space for textures and other visual data. The game uses eight-bit paletted textures to cut the cost. These textures take far less memory than full RGBA images. The tools also resize assets to suit the PSP’s hardware requirements and generate mipmaps in advance. Every kilobyte counts.

That’s one of the most impressive parts of the project. OpenStrike doesn’t simply cram a PC-style game into limited hardware and hope for the best. It plans around the limits from the start. CPU time, system memory, video memory and data transfer all have strict budgets. The engine stays inside them by controlling exactly what gets loaded, updated and drawn.

Testing a PSP game with modern tools

OpenStrike also uses a surprisingly modern testing setup. The game runs at a fixed 60Hz time step, uses seeded randomness and supports scripted input. That makes test sessions repeatable. Run the same input sequence twice, and the game should produce the same result. Automated tests can launch the PSP build through PPSSPP, feed it a known series of controls and compare the output against reference images.

That helps catch problems in movement, collision, weapons, animations, bots and round logic. It also makes it easier to compare the desktop and PSP versions. Manual testing still matters, especially for performance. The developers measure frame timing on a real PSP, then transfer the results back to the development system for analysis. Emulation can confirm whether something works. Only physical hardware can confirm whether it works within the real machine’s limits.

Why this project matters

OpenStrike is impressive because it doesn’t take the obvious route. The simplest approach would have been to write everything in C or C++, build a fixed HUD and create a one-off PSP version. That probably would have worked. Instead, the project combines a Rust engine with JavaScript game logic and a reactive user interface. That sounds excessive for a handheld from 2004.

In practice, it creates a cleaner system. Rust handles work that needs speed, precise timing and direct hardware access. JavaScript handles rules, tuning and interface behaviour. The game can change quickly without forcing the native engine to change with it. The project also gives a more honest view of JavaScript performance.

JavaScript isn’t rendering the 3D world. It isn’t calculating every collision or running the full simulation. It’s doing the work that suits it best. That’s why the design works. The developers didn’t try to prove that JavaScript can replace everything. They used it where flexibility matters and kept the demanding systems native. OpenStrike ends up being much more than a technical stunt.

Yes, it puts a Counter-Strike-style shooter on a PSP. That alone will get attention. But the more interesting story sits underneath the gunfire. It shows that modern development ideas can work on very old hardware, provided the engine respects the machine. Every frame has a limit. Every texture has a cost. Every update needs a reason. OpenStrike understands that. And that’s why it runs.

Spread the love
error: