惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
J
Java Code Geeks
Jina AI
Jina AI
罗磊的独立博客
宝玉的分享
宝玉的分享
S
SegmentFault 最新的问题
D
DataBreaches.Net
博客园 - 叶小钗
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Google DeepMind News
Google DeepMind News
阮一峰的网络日志
阮一峰的网络日志
B
Blog
V
Visual Studio Blog
雷峰网
雷峰网
博客园 - 【当耐特】
Apple Machine Learning Research
Apple Machine Learning Research
Engineering at Meta
Engineering at Meta
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How I Built a Real-Time Robot Battle Simulator from Scrat...
Ali Haggag · 2026-05-24 · via DEV Community

A CS student's journey from a blank repo to a production platform with a custom scripting language, 60fps physics engine, and 3,000+ lines of battle-tested TypeScript.

The Idea

I wanted to build something that made competitive programming fun. Not another LeetCode clone. Something where your algorithm doesn't just pass a test case — it fights.

The concept: players write code to control robots. The robots battle in real-time. Your logic vs the world.

That's Logic Arena.

Starting From Zero — The Engine

The first challenge was building a game engine from scratch. No Unity, no Phaser — pure TypeScript.

Version 0.2.0 was just two robots moving in a canvas. But getting there required solving the first real technical scar:

The Singleton Problem. Two NestJS services were sharing the game engine — or so I thought. They each had their own instance, so state was completely desynced. The fix: @Global() decorator to enforce a single shared engine across the entire module.

@Global()
@Module({
  providers: [GameService],
  exports: [GameService],
})
export class GameModule {}

Enter fullscreen mode Exit fullscreen mode

One decorator. Three hours of debugging.

Building AliScript — A Custom Scripting Language

This was the craziest decision I made. Instead of using JavaScript or Lua for robot scripting, I built my own language.

Why? I wanted players to think algorithmically, not just copy-paste code. AliScript had to be simple enough for beginners but powerful enough to reward expert thinking.

The pipeline:

String Script → Lexer → Tokens → Parser → AST → Server Evaluator → Robot Actions

Enter fullscreen mode Exit fullscreen mode

First version supported basic conditionals:

IF CAN_SEE_ENEMY
  FIRE
END
MOVE

Enter fullscreen mode Exit fullscreen mode

By v2.4, it became Turing-complete-ish:

WHILE TRUE DO
  IF CAN_SEE_ENEMY AND MY_ENERGY > 30 DO
    BROADCAST(NEAREST_VISIBLE_X)
    BURST_FIRE
  ELSE IF IN_STASIS DO
    WAIT
  ELSE DO
    SCAN
    PATHFIND
  END
END

Enter fullscreen mode Exit fullscreen mode

The hardest bug? Operator precedence.

2 + 3 * 4 was evaluating to 20 instead of 14. Every multiplication-heavy script was silently computing wrong values. The fix required splitting parseBinaryExpression() into two separate precedence levels — parseAddition() and parseMultiply().

The Performance Crisis

By v1.3.0, the arena was running at ~15fps. Profiling revealed the culprit:

3,862ms scripting bottleneck — the main thread was choking on useState updates 60 times per second.

The fix was a dual-state architecture:

// Before: useState causes re-render on every tick
const [gameState, setGameState] = useState(null);

// After: useRef for game logic, throttled state for UI only
const gameStateRef = useRef(null); // updates at 60fps, zero re-renders
const [uiState, setUiState] = useState(null); // updates at 10fps, DOM only

Enter fullscreen mode Exit fullscreen mode

Scripting time dropped from 3,862ms to near zero.

Six Performance Fixes in One Release

By v2.5.0, I ran a full profiling audit and found six simultaneous bottlenecks:

1. Obstacles in every WebSocket payload — static data sent 10x/sec for no reason. Fix: initialize once, strip from all subsequent payloads.

2. 30 WebGL draw calls for obstacles — rewrote to THREE.InstancedMesh. 30 draw calls → 4 draw calls.

3. 10 useFrame JS callbacks for obstacle animations — moved all pulse math to GPU via fragment shaders. 0 JS callbacks per frame.

4. Server memory leak — replay snapshots were deep-cloning unboundedly. Added ring buffer capped at 300 objects.

5. The Ghost Match Massacre — when players closed their browser, the physics engine kept running at full speed indefinitely. Hundreds of ghost matches accumulating CPU in silence. Fix: wired disconnect lifecycle to stop the engine the moment the last player leaves.

The Deployment Nightmare

Going from localhost to production at logicarena.dev was a gauntlet.

The 2.57GB Docker Context Bomb — first build transferred 2.57GB to the Docker daemon because node_modules wasn't excluded. Fixed .dockerignore, dropped build context to 15MB.

The Prisma Ghost Engine — Alpine Linux refused to execute the Windows-compiled Prisma binary. Added linux-musl to binaryTargets.

The WebSocket CORS Wall — every Socket.IO connection rejected because the gateway was hardcoded to localhost:3000. Extended CORS array, fixed Nginx WebSocket proxy headers.

The Silent Postman — DigitalOcean silently blocks outbound SMTP on new Droplets. Zero errors, zero delivery, just void.

The Architecture Today

logic-arena/
├── apps/
│   ├── client/     # Next.js 16, React Three Fiber, PWA
│   └── server/     # NestJS 11, Socket.io, JWT
└── packages/
    ├── engine/     # Custom TypeScript physics engine
    └── logic-parser/ # AliScript lexer, parser, evaluator

Enter fullscreen mode Exit fullscreen mode

What I Learned

1. Architecture decisions compound. Every "quick fix" that bypassed the module system created three bugs later.

2. Profile before optimizing. The 3,862ms bottleneck was invisible until I actually measured it.

3. Custom languages are feasible. An AST evaluator is just a recursive tree walker — intimidating name, straightforward implementation.

4. Ship early, iterate fast. Logic Arena went from 2 robots on a canvas to a 60-level algorithmic campaign in 4 months of solo development.

Try It

Live: logicarena.dev — no account required, join as guest.

GitHub: Ali-Haggag7/logic-arena

Write your first script, watch your robot fight, and tell me what you think in the comments!