A puzzle of perspectives. Roll around the edges of a floating world.
A third-person gravity puzzle: roll your sphere across, around and underneath floating islands of cubes, jumping gaps and dodging spikes and molten tiles to collect every key before the portal unlocks. 24 hand-built levels across four living worlds, with coins to bank and new materials to unlock for your sphere.
Made by jaydemks. Released under the MIT license — original source.
Changes for this platform: Patched src/progress.js: readProgress()/saveProgress() previously defaulted their `storage` parameter to `globalThis.localStorage` directly in the parameter list, so merely calling either function with no second argument (as src/main.js always does) threw a SecurityError in this sandbox's opaque-origin iframe -- and because the throw happened while evaluating the parameter default, it fired before the function body's own try/catch ever ran, crashing the game at boot on every load. Changed both parameters to default to `undefined` and added a getStorage() helper that resolves window.ArcadeSDK.storage first (wrapped in a getItem/setItem/removeItem adapter), guarded in its own try/catch, falling back to real localStorage (also guarded) only when ArcadeSDK is absent, i.e. the game is run standalone outside the platform. Added src/arcade-bridge.js (new file, imported only for its side effects from src/boot.js ahead of src/main.js) implementing the ArcadeSDK bridge: window.__orbitOnReady() -> SDK.ready() (idempotent, since src/main.js's buildMenu() re-runs whenever the player backs out to the menu); window.__orbitOnScore(score) -> SDK.score(n) (de-duplicated so repeated identical scores are not re-sent); window.__orbitOnGameOver({score,won,level}) -> SDK.gameOver(...) plus SDK.submitScore(score) on a win, since this game's own per-level 'best' bank in src/progress.js is its closest thing to a leaderboard. Also wired SDK.onPause/onResume in arcade-bridge.js to two new hooks, window.__orbitPause/__orbitResume, defined at the bottom of src/main.js: __orbitPause clears held input and calls the existing game.pause(true) (mirroring the file's own window 'blur' and 'visibilitychange' handlers); __orbitResume unlocks/resumes the WebAudio context only, leaving the game on its own pause screen until the player taps Resume, matching how the game already behaves after a tab-blur pause. Added five single-line hook calls to src/main.js at the exact points described above: inside the onChange callback passed to `new Game(...)`; inside the onEvent callback's 'won'/'lost' handling; at the end of buildMenu(); and the two window.__orbitPause/__orbitResume definitions appended after the existing requestAnimationFrame(frame) call. No other game logic in main.js was touched. No network calls, ads, analytics, external/CDN fonts, service worker or online leaderboard existed anywhere in the upstream source (confirmed by grepping src/ and index.html for fetch/XHR/localStorage/cookie/indexedDB/analytics/cdn/http(s):// -- the only hit was the two progress.js localStorage defaults above); all audio is synthesized locally with WebAudio oscillators (src/audio.js, unchanged) and every texture/geometry is generated procedurally at runtime (src/environment.js, src/scene.js, unchanged), so nothing else needed stripping. Kept the bundled @fontsource/dm-sans and @fontsource/manrope packages exactly as upstream ships them -- Vite inlines them as local woff/woff2 files during the build (see CREDITS.md for their SIL OFL license). Built with `npm ci && npm run build`; vite.config.js already set base: './', so Vite's own asset fingerprinting already emitted every path relatively (index.html and the built CSS/JS reference only ./assets/...), confirmed by grepping the dist output for absolute '/'-rooted paths and finding none. Copied only dist/* plus the upstream LICENSE into this folder; no source maps were generated, so none needed stripping. Did not need to patch keyboard handling: upstream's src/main.js keymap already reads event.code (ArrowUp, KeyW, etc.), not legacy keyCode, so the platform's touch-shim's synthetic KeyboardEvents already work unmodified. Did not enable the platform's own on-screen dpad/joystick overlay -- meta.json sets touch.scheme to 'native' because the upstream UI (src/ui.js) already ships its own on-screen left/forward/back/right/jump buttons (shown at @media(pointer:coarse) in src/style.css) that dispatch the same 'orbit-control' CustomEvent src/main.js already listens for; adding the platform's generic dpad on top would have doubled up the controls. Did not rename the game or alter any in-game level/world/skin names -- none referenced real people, trademarks or private messages.
Comments 0
Log in to comment.