1 · The build
A folder with index.html at its root, ≤ 50 MB, ≤ 1,500 files. The page runs under a Content Security Policy: scripts, styles and assets only from the build itself, network only to the hosts you declare with --servers https://your-game-server (https and wss). Add cover.png (16:10) for the card. Load the SDK: <script src="/sdk/v1.js"></script> and call await Freeplay.init().
2 · The command
# inside your agent, with the Freeplay MCP server installed:
# freeplay_publish { dir, slug, title, players, tags, servers, ai_assisted, live }
# or the CLI:
node freeplay/packages/publish/freeplay-publish.mjs ./dist --slug my-game --title "My Game" \
--players multi --servers https://your-game-server --tags io,arcade --ai --liveThe first upload creates the listing; every later one is a new version. Nothing goes live until you say --live. The command waits for the scan — virus signatures, code patterns, a 30-second run in a real browser, a review — and prints the verdict; a refused build prints the reasons.
3 · The SDK, in one screen
fp.gameplayStart() / fp.gameplayStop()the play counter; loadingStart() / loadingStop() for the framefp.save(obj) / fp.load()cloud when signed in, localStorage otherwise; fp.user → name and id, or nullfp.room.create(myRoomId)a six-letter code and link; fp.room.joining() → the room a friend arrived for; fp.onJoin(fn)fp.score(value, { board }) · fp.top({ board, limit })leaderboards, best kept per playerfp.products() · fp.buy(sku) · fp.owned() · fp.consume(sku, n)purchases through web checkout; list products on your account page. Save before buy.fp.ad('midgame' | 'rewarded')→ { shown, rewarded }; grant nothing unless rewarded is true. Off by default.fp.settings.muteAudio · fp.onSettings(fn)the arcade's mute wins. Outside the arcade every call is a safe no-op.4 · The deal
No exclusivity, 70% of net to you when ads or purchases are on, free for three games, month to month. The whole thing is written down at /creators.
5 · The stage
Open on your own menu. The player arrives from a static page that shows your cover, the room code and the leaderboard, and chooses to enter — so the first thing they should meet is your menu, where sound, controls and how to play live. Do not drop them straight into a match. Inline, your game gets the whole content column — 1168 × 657 on a desktop wrap, 16:10 on phones — and fullscreen on demand. Lay out from window.innerWidth / innerHeight on every resize (the arcade re-fires it after fullscreen changes) and never assume a minimum width: a menu designed for 1920 must fit 1168 and 390.
6 · The rules
Say so if AI helped make it (--ai); it is shown on the page, never used against you. Your game, your IP, no exclusivity. Originality: no clones, no asset flips. Nothing that targets children. Refusals come with the reasons and you can publish again.