Public platform · v1
Bring the arcade into your world.
Discover every URSY.games room through a free, keyless JSON API, then render the selected game through one stable player URL. It is designed first for the Radical AI spatial desktop and deliberately open enough for websites, launchers, classrooms and experiments.
- No API key
- Read-only
- Wildcard CORS
- CDN-cacheable
One clean contract
Built for Radical, useful everywhere.
Radical does not need to understand 203 different codebases. It asks the catalogue what is available, opens the returned embed URL, and talks to every player through the same bridge.
- 01Discover
Filter the catalogue by category, play mode, engine, licence, input or search text.
- 02Place
Render links.embed in a web panel, spatial surface or ordinary responsive iframe.
- 03Control
Pause hidden rooms, restart a session, mute sound and send virtual keys with bridge v2.
- 04React
Wait for the normalised ready event and listen for player state, exit and result events.
REST endpoints
A small API with useful answers.
Base URL: https://ursy.games/wp-json/ursy-games/v1
| Method | Path | Purpose | Browser cache |
|---|---|---|---|
| GET | /games | Paginated catalogue with filters and compact or full views. | 5 min |
| GET | /games/{slug} | One game, including editorial copy, instructions, tips and launch links. | 10 min |
| GET | /manifest | The complete compact release for clients that maintain their own library. | 1 hour |
| GET | /categories | Stable category slugs, display names and current counts. | 1 hour |
| GET | /licenses | Licence groups, source collections and local notices. | 1 hour |
| GET | /daily | One deterministic game of the day, identical for every visitor. | 15 min |
| GET | /status | Release version, catalogue hash, totals and bridge support. | 1 min |
| GET | /openapi | Raw OpenAPI 3.1 document for generators and agents. | 1 hour |
Quick start
From catalogue to playable room.
Every response is JSON and carries cache validators, release headers and the catalogue SHA-256. No credentials or cookies are required.
const response = await fetch('https://ursy.games/wp-json/ursy-games/v1/games?category=puzzles&per_page=12');
const { items } = await response.json();
for (const game of items) {
console.log(game.name, game.links.embed);
}<iframe src="https://ursy.games/embed/battleship/" title="Play Battleship" allow="fullscreen; autoplay" loading="lazy"></iframe>Player bridge v2
One message language for every game.
Send JSON objects with window.postMessage. The embed accepts commands only from its parent or top-level host; its game iframe remains sandboxed. A parent may use any origin because the service is intentionally public and keeps no privileged player state.
Host → player
ursy-games:lifecyclestate:pausedorrunningursy-games:restart- Reset the active room.
ursy-games:mutemuted:trueorfalseursy-games:keykeypluspressedfor spatial controls.ursy-games:focus- Move keyboard focus into play.
Player → host
ursy-games:ready- Includes slug, engine, sequence and capabilities.
ursy-games:state- Loading, paused, running, muted, audible or fullscreen changes.
ursy-games:result- A result when a supporting game completes.
ursy-games:exit- The player used its own exit control.
const player = document.querySelector('iframe');
player.contentWindow.postMessage({
type: 'ursy-games:lifecycle',
state: 'paused'
}, '*');
window.addEventListener('message', ({ data }) => {
if (data?.type === 'ursy-games:ready') {
console.log(data.slug, data.capabilities);
}
});Deliberate constraints
Cheap to operate. Hard to abuse.
Read-only first
Everything the catalogue publishes is read-only and needs no key. The two writes that do exist are the leaderboard ones — posting a score and claiming a public handle — and both require a signed-in URSY.ID. Nothing else in the play path stores anything about a player. (Corrected 5 September 2026: this card used to say version 1 had no score writes at all, which stopped being true when the leaderboard shipped.)
Cache the facts
ETags, catalogue hashes, public cache headers and deterministic daily selection let browsers, CDNs and Radical reuse responses instead of repeatedly waking WordPress.
Sandbox the code
Imported games run in constrained same-site frames. Games need no external network call while playing, and lifecycle messages stop hidden rooms wasting CPU.
Licence every room
Each record names its own licence, pinned source and notice. Using an URSY embed is straightforward; redistributing the underlying files still means following that game’s licence.
Two steps ahead
Where the open platform can go next.
The useful next work is client-side and cacheable—not a costly social backend. These layers can be added without changing today’s URLs or bridge.
- Now
Catalogue API + universal embed
The stable foundation shipped here: discovery, metadata, licensing, launch URLs and lifecycle control.
- Next
Radical adapter
A tiny typed client or web component can turn “open Battleship” into catalogue lookup, spatial panel creation, automatic pause-on-hide and controller mapping.
- Then
Offline game packs
Use the manifest hash to pre-cache a curated set—puzzles, cards or low-input rooms—so Radical can open favourites instantly and survive a weak connection.
- Later
Portable challenges, no accounts
Encode seeds, difficulty and local challenge rules into shareable URLs. Friends can play the same setup without URSY.games storing identities or running a live match server.
Open by design
Build something playful.
The catalogue endpoint is free and public. Cache responses, link back where it makes sense, and inspect the licence object before copying game files into another distribution.