BeamNG.Earth
BeamNG.drive용 1:1 비율 실시간 지구, 실제 고도·위성 이미지·부동 원점·보조 서버에서 LOD 스트리밍
고전 게임에 새로운 차원, 실시간 영토 뱀 게임으로 듀얼(AI 대전)·솔로 모드 제공, 집을 떠나 루프를 닫고 영토를 차지
Classic game, new dimension: a real-time territory snake game with Duel (vs AI) and Solo modes. Leave home, close loops, capture land.
게임TypeScript · CSSGitHub @brookyuri온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Real-time territory snake game — Duel vs AI and Solo modes, PixiJS 2026 renderer + 8-bit classic theme. TypeScript, React, Vitest.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
▶ Play — https://territory-snake.vercel.app (best on a phone)
A real-time territory game for the mobile browser, with two modes:README 전문 보기 ↗▶ Play — https://territory-snake.vercel.app (best on a phone)
A real-time territory game for the mobile browser, with two modes:
In both modes the snake moves on its own; you only steer.
Two looks, switched in the menu (1986 | 2026):
Reduced motion turns effects off in both looks (and makes the 2026 board move cell by cell).
Built as a portfolio project and a game-design experiment: the rules are specified up front, the engine is pure and tested, and the bot is explainable.
https://territory-snake.vercel.app — best on a phone. Add ?perf to the URL to see tick timing, frames per second and board frame time, and copy a performance report from the end screen. If ticks run late on the 2026 board, the game offers to switch to 1986 once.
Auto-deployed from master via Vercel.
npm install
npm run dev # dev server
npm run build # static build in dist/ (relative paths, deployable to any sub-folder)
npm run preview # serve the build locally
Controls: swipe on the board or tap the D-pad on phones; arrow keys or WASD on desktop. Space or P pauses (hiding the tab pauses too). The menu picks the mode (Duel / Solo), the difficulty (Easy / Normal, remembered per mode; for Duel it is the bot) and the speed (Slow 400 ms, Normal 280 ms, Fast 180 ms per tick).
npm test # unit tests, 2000-game invariant stress tests for Duel and Solo, a quick bot smoke match
npm run bench # full bot tournament: win rates, P1/P2 balance, move timing (~1.5 min)
Measured on 2026-09-29 on this repository (npm test, npm run bench, a production build in headless Chromium on an Intel UHD laptop GPU).
Tests: 257 unit and scenario tests in 30 files (npm test).
Stress, Duel: 2000 seeded random-vs-random games; the state invariants are checked after every round — 0 violations.
Stress, Solo: 2000 seeded random-snake games (up to 3000 ticks each); invariants checked after every tick — 0 violations.
Bot benchmark (npm run bench, seed 20260926, sides alternate), Normal bot win rate:
| Normal vs | Games | Wins | Losses | Draws |
|---|---|---|---|---|
| random | 500 | 100.0% | 0.0% | 0.0% |
| safe | 500 | 99.2% | 0.6% | 0.2% |
| easy | 500 | 75.2% | 24.2% | 0.6% |
Normal bot move time: 0.26 ms mean, 0.85 ms p99 over 105,159 moves.
Performance (Fast speed, 180 ms per tick, 375×667, 45 s per run, no CPU throttling): 0 late ticks in Duel and Solo in both looks. 2026 board frame time: 0.81 ms average / 1.6 ms p95 in Solo, 1.03 ms / 1.9 ms in Duel, ~59 FPS; single frames reach ~33 ms.
Bundle (gzip): main JS 74.8 KB; the PixiJS code loaded for the 2026 board, as separate lazy chunks, 119.9 KB (core 81.2 + WebGL 19.7 + render targets 14.9 + 4.1). The 1986 look never downloads it.
src/engine/ — the game rules as pure TypeScript with no UI imports: createInitialState, getLegalMoves, resolveRound → { state, events }, the capture algorithm and runtime invariants.src/engine/solo/ — Solo on top of the same legal moves, trail update and capture: createSoloState, resolveSoloTick → { state, events }, seeded bouncing balls, lives and levels, invariants S1–S6.src/bot/ — computer opponents built only on the public game state: position analysis (distance home, distance to a trail, potential capture), randomBot, safeBot, normalBot (a one-round maximin over a weighted evaluation, weights in NORMAL_CONFIG, choices explained by explainMove) and easyBot on top of it (EASY_CONFIG: slower reactions, mistakes, less caution).src/game/ — the real-time loop without React: a shared tick controller with an injectable clock (countdown, drift-free ticks, pause), the two-press input queue and the wall rule. The Duel match computes bot decisions as generators in small slices between ticks; the Solo match adds short in-game holds (a lost life, a cleared level) before the next countdown.src/render/ — the renderers: the board behind one interface, BoardRenderer (mount / update on each tick / frame(alpha) on each animation frame / resize / destroy). Adapters turn a Duel or Solo state into a neutral RenderSnapshot (land by cell, trails as ordered cell lists, heads, balls). Dom8bitRenderer is the 1986 board; Pixi2026Renderer (PixiJS v8, lazy-loaded chunk, WebGL with a Canvas fallback) draws the 2026 one from pure geometry helpers (body polyline, tail taper, arc-length dashes, interpolation).src/render/pixi2026/ — the 2026 board: land cached in a RenderTexture (only changed cells are redrawn), per-snake render groups, sprite pools for particles, effects played only from engine events.src/ui/ — React + Tailwind screens (menu, how to play, game, pause) that drive the match controller and draw its state and events; no game logic lives here. src/ui26/ holds the 2026 versions of the screens.localStorage ( for Duel, for Solo, for every game) and can be exported as JSON from the menu.The rules are the single source of truth: see GAME_RULES.md for Duel and SOLO_RULES.md for Solo. The 2026 look is specified in VISUAL_2026.md. The original turn-based concept is kept as history in docs/history/PRD-v0.1.md.
computeCapture serves both modes, the bot and the stress tests.explainMove prints the per-term scores, so a surprising move can be traced to a weight. No ML and no LLM; the Easy bot is the same search with slower reactions and deliberate mistakes.state + moves → state + events) with no timers or UI. The real-time loop is a small controller with an injectable clock (countdown, drift-free ticks, pause, input queue), so tick timing is unit-tested with fake clocks and the same engine plays the 2,700-game bot tournament headless in about 36 s.BoardRenderer (mount / update per tick / frame(alpha) per animation frame) has a DOM implementation for 1986 and a PixiJS one for 2026, fed by a neutral snapshot built from engine state. The budget was set first (0 late ticks at Fast, frame ≤ 16 ms); profiling drove the fixes: land cached in a RenderTexture with per-cell redraws, straight moving segments as stretched sprites, alpha instead of visible toggles, per-snake render groups, and a warm-up during the countdown. After the renderer refactor the 1986 screens were checked pixel-for-pixel against the previous build.Development followed specifications written in Markdown before the code: the rules (GAME_RULES.md, SOLO_RULES.md) with numbered test scenarios, the visual spec (VISUAL_2026.md) and the original product brief (docs/history/PRD-v0.1.md). Work went in short sessions, each with a written task, per-step commits and a report with measurements (stress tests, frame and tick timing, bundle size, pixel comparison of the 1986 screens).
The code was written with Claude Code.
2026:
| Menu | How to play | Duel | Capture wave | Trail in danger |
|---|---|---|---|---|
| Solo | Ball hit | Level clear | Game over | Pause |
|---|---|---|---|---|
1986 board, Duel:
| Menu | How to play | Game | End screen |
|---|---|---|---|
1986 board, Solo:
| How to play | Game | Ball hit | Level clear | End screen |
|---|---|---|---|---|
ts_statsts_solots_games