Snarky's
LOADING
WASD / ArrowsMoveMouseAimClick (hold)FireP / EscapePause
shooter#twin-stick#shooter#arcade#wave-survival#score-attack

Blast the robots. Save the family. Survive the waves.

A neon twin-stick shooter: fight through endlessly escalating waves of robots in a glowing arena, rescue stranded family members for big score bonuses, and dodge the robots that can't be shot. Move with WASD or the left stick, aim and fire with the mouse or the right stick.

0 plays0 players0 remixesPublished 6d ago
Open source

Made by Frank Force. Released under the MIT license — original source.

Changes for this platform: index.html (copy of games/roboRescue.html): rewrote the three ../templates/ script src paths to ./ (engineLoader.js, gameFx.js, menus.js) so the game is self-contained with no path leaving this folder; added a <script src="./arcade-bridge.js"> tag after menus.js and before the game's own inline <script>; changed <title> from 'LittleJS Robo Rescue' to 'Robo Rescue'; reworded one dev comment from 'Robotron 2084-style twin stick' to 'Twin-stick rescue shooter' (a few other internal comments citing Robotron 2084 as the source of the arcade-accurate scoring/wave-data values were left as-is — they document research provenance, are never shown to the player, and weren't adjacent to any other patch); renamed the internal save-key string passed to saveDataInit() from 'robotron' to 'roboRescue' (an opaque storage key, never shown to the player; safe rename since this is a fresh save with no migration need). engineLoader.js: upstream templates/engineLoader.js replaced with the platform's pre-patched templates/engineLoader.ARCADE.js (renamed) — rewrites the engine path from ../dist/ to ./, wraps the littlejsBuild() console helper's direct localStorage calls in try/catch, and redefines readSaveData/writeSaveData to route through window.ArcadeSDK.storage when present (so best-score and the engine's medal system persist via the host instead of throwing against the sandboxed iframe's real localStorage), falling back to upstream's own already-guarded localStorage behavior when run standalone. gameFx.js, menus.js: copied verbatim from templates/. littlejs.release.js: copied from dist/ with one line changed in glInit() — glCanvas.getContext('webgl2', {antialias:glAntialias}) to glCanvas.getContext('webgl2', {antialias:glAntialias, preserveDrawingBuffer:true}) — so the WebGL canvas's backing buffer survives an out-of-frame readback (e.g. the platform's own headless QA check) instead of the browser being free to clear it right after presenting; same fix class as the reference hexgl-racer port applied to its Three.js renderer, no visual or gameplay effect. arcade-bridge.js: new file, not present upstream. Calls SDK.ready() once, the first time menus.js's addPlayingListener fires (always 'false', since this runs before gameInit, matching the title/attract screen). Reports SDK.score() from a 500ms poll of the game's own `score` variable (polling, rather than wrapping gameUpdatePost, because gameUpdatePost is handed to engineInit() by value at the bottom of the inline script, so reassigning it afterwards would never be seen by the running engine loop). Wraps menus.js's global submitBestScore(n) — the game's one and only run-end call site (Player.damage(), on the last life lost) — to call SDK.gameOver({score, won:false}) and SDK.submitScore(score) before invoking the original (this game has no win condition; waves repeat forever, so won is always false). Wires SDK.onPause to call showMenu('pause') when isPlaying(), matching exactly what the game's own Escape/gamepad-Start handling already does; SDK.onResume is a no-op guard, leaving resume to the player's own RESUME click, same as the platform's own recommended pattern. No gameplay logic, values, sprites, sounds, or balance were changed from upstream.

Comments 0

Log in to comment.

  • Loading…