Threats Defender is a cybersecurity arcade game built in React — a browser-based shooter where players intercept viruses, ransomware, and phishing attacks while absorbing one-sentence lessons about what each threat actually does. If you’ve ever wanted to combine React TypeScript game development with real security awareness training, this project delivers both in a single, playable codebase.
🎮 What Is Threats Defender?
Threats Defender is a Space Invaders-inspired arcade shooter with a cybersecurity education layer baked in. The player controls a shield icon along the bottom of the screen, slides left and right, and fires glowing cyan beams at incoming threats — viruses, malware, ransomware, spyware, trojans, worms, and phishing mails — before they cross the firewall boundary.
Every destroyed threat triggers a toast notification naming the threat and delivering a plain-language definition. Spyware silently collects user data. A trojan disguises itself as legitimate software. Ransomware locks your files and demands payment. You read these between shots, which means the definitions stick in a way a slide deck never achieves.
🛠️ Tech Stack — React, TypeScript, Vite, Tailwind
The entire game runs in the browser with zero backend and no game engine. The stack is:
- React — component tree for HUD, modals, and entity rendering
- TypeScript — strict types for every game object (
Threat,Beam,DataObject,GameState) - Vite — instant dev server and fast production builds
- Tailwind CSS — all visual effects including neon glow and health-bar transitions are utility classes;
boxShadowhandles effects Tailwind can’t express inline
You can explore the official React docs and Vite docs to go deeper on either tool. For TypeScript game typing patterns, the TypeScript handbook covers the generics and intersection types used throughout types/game.ts.
⚡ How the Game Engine Works (No Library Required)
All mutable game state — positions, velocities, health, active entity lists — lives in refs, not React state. This is the key architectural decision. Storing game objects in useState would trigger a full component re-render every frame, which at 60 fps is 60 re-renders per second. Instead, a single tick counter held in state increments each frame, and React re-paints only that counter change while refs hold the authoritative game world.
The loop itself uses requestAnimationFrame with a capped delta time (Math.min(dt, 0.05)) to prevent the spiral-of-death when the tab loses focus and frames bunch up.
Threat spawning uses a weighted random picker (pickWeighted()) that samples by each threat type’s spawnWeight property. Rarer threats like Ransomware and Worm appear less frequently at low levels without needing explicit level gates — the weights handle it automatically.
📊 Scoring, Levels, and Difficulty Scaling
The level formula is simple and transparent:
level = Math.floor(score / 500) + 1
Every 500 points, the level steps up. With each level, threat speed scales by 12% and the spawn interval shrinks toward a 400ms floor. Higher-value threats are worth more because they deal more breach damage — Ransomware and Worms hit the system for 25 health points each, making them the priority targets.
The all-time best score persists to localStorage under the key threats-defender-best-score and loads the moment the page opens. Beat the record mid-game and the HUD updates live.
🎯 Four Movement Patterns
Four distinct movement patterns make threat interception non-trivial:
- Straight — glides left to right at constant speed
- Zigzag — alternates vertical direction at a fixed interval
- Wave — undulates based on horizontal position, curving as it travels
- Dash — sprints forward in sudden bursts, requiring a lead shot to intercept
At higher levels, wave and dash threats dominate, which forces players to reposition constantly rather than camping one spot.
🔍 Collision Detection From Scratch
Collision checks use axis-aligned bounding box (AABB) math — center distances compared against the sum of half-widths on both axes. A dead-entity Set prevents double-processing when a beam hits two overlapping threats in the same frame. When system health reaches zero, the final score increments and a toast queues for the next render cycle.
The game over screen shows a full defense report: every threat type encountered, how many were destroyed, how many breached, and an overall defense-rate percentage. Above 70% is green (firewall held). Below 40% is critical.
FAQ
How do I build a browser game with React without a game engine?
Store all mutable game state (positions, velocities, entity lists) in refs rather than React state to avoid per-frame re-renders. Drive the loop with requestAnimationFrame, update refs each tick, and use a single state counter to trigger repaints. This gives you a real-time game loop inside a standard React app.
What cybersecurity threats should beginners learn first?
Start with phishing, malware, and ransomware — these are the three most commonly encountered threats in the real world. Phishing tricks users into revealing credentials, malware is any software designed to cause harm, and ransomware encrypts files and demands payment. Threats Defender covers all three plus spyware, trojans, and worms.
Can you do collision detection in React without a physics library?
Yes. Axis-aligned bounding box (AABB) collision is sufficient for most 2D arcade games. Compare center-to-center distances against the sum of half-widths on each axis. If both axes overlap, you have a collision. No library needed.
How does localStorage best score work in a React game?
Read the stored value once on mount using localStorage.getItem(), parse it, and store it in a ref. Each time the game ends or the score updates, compare the current score against the stored best and write back with localStorage.setItem() if the current score is higher.
Is this project good for learning TypeScript?
Yes. The project defines strict intersection types for every game entity (Threat extends GameObject, Beam extends GameObject) and uses discriminated unions for movement patterns. It’s a practical TypeScript exercise because the types are enforced at runtime through game logic, not just as annotations.
✨ Key takeaways
- ✅ A cybersecurity arcade game in React is buildable without any game engine — refs + rAF are enough
- ⚡ Storing game objects in refs instead of state eliminates per-frame re-renders and keeps the loop smooth
- 🎯 Weighted random spawning controls threat frequency without hard level gates
- 📊 AABB collision detection handles every hit check in ~5 lines of math
- 💡 Kill toasts that deliver one-sentence threat definitions make cybersecurity concepts stick through repetition
- 💻 localStorage persistence for best score requires zero backend — one
getItemon mount, onesetItemon update
Clone the repo, add your own threat types, and ship your own cybersecurity arcade game — the full starter kit is in the shop.
❤️ Support Platforms
- Ko-fi: https://ko-fi.com/codingfab
- Buy Me a Coffee: https://buymeacoffee.com/codingfab
- Patreon: https://patreon.com/Coding_Fab




