Raw Markdown โ ยท Manifest generator โ
Make a game for Cubby Arcade
Cubby Arcade is a controller-first arcade for pre-literate children. This guide is for adults and coding agents; the games themselves must not require reading.
Start with the player
Use pictures, animation, sound and demonstrated actions, not written tutorials, menus or error messages. A button glyph can supplement an action but must not be the only explanation. Support keyboard and controller, with touch controls when appropriate. Line Cutter is a technical test payload, not a UX template.
Build an offline web game
Ship static HTML, JavaScript, styles, artwork and audio with relative asset references. The entrypoint and all required assets must work without a network. Do not depend on your website's server routes, root-relative game assets, logins, CDNs or browser storage tied to the publishing domain. Cubby installs each game under /games/<id>/; it does not navigate to the remote game's website.
Use a stable lowercase game ID such as my-game. Keep saves compatible between versions or migrate them. Keep old release files available.
Controls, lifecycle and saves
The optional shared JavaScript modules live in runtime/core/ in the Cubby repository. They are not an npm package. Existing Handheld* names are compatibility APIs, not outdated instructions. Inspect those modules before integrating:
preferences.jsandinput.js:HandheldInput.createInput({onAction})provides semantic input. Direction buttons retain their names;amaps toconfirm,btoback, andstarttopause. The event also containsbuttonandsource. Keyboard mappings follow user preferences.platform.js:HandheldPlatform.createPlatform()exposes capability-based services.platform.saves(gameId)returnsget(name),set(name, value)andremove(name)for JSON saves. The native bridge is host supplied; do not invent a server-side save or wallet API.sdk.js:HandheldSDK.createGameHost({gameId, platform})optionally connects shared input, pause/resume and saves. Its game instance haspress(button),stop(),wake()and optionallystart(). Follow the actual source and its tests for lifecycle details.controls.js: optional pictorial controls viaHandheldControls.createControls(input, 'game').
Cubby injects a host-owned game menu even if you do not use the SDK. Escape, Select + Start, or both shoulders open it. Do not intercept or repurpose that system menu. Listen for handheld:system-menu (event.detail.open) to pause your own simulation and audio while it is open; pause on lost focus/visibility. The injected menu alone cannot automatically pause an arbitrary game loop.
Publish once, without a ZIP
- Build offline files into
dist/game/. - Download the standalone manifest generator.
- Generate sizes, SHA-256 hashes and versioned URLs from those exact files.
- Upload the unchanged files to your own HTTPS domain under a versioned path.
- Verify the upload, then publish the stable manifest last, in that same GitHub release workflow. No second release or hand-entered checksums.
uv run python tools/cubby_manifest.py dist/game \
--id my-game --version "$RELEASE_VERSION" \
--entrypoint index.html --artwork cover.png \
--base-url "https://my-game.example/releases/$RELEASE_VERSION/" \
--output dist/release-manifest.json
The generator is Python 3.11+ and standard-library only; copying it into your repo does not require installing Cubby. Keep its output outside dist/game/. See the complete release manifest specification for fields, validation, size limits, media and compatibility.
Add the game to the store once
Cubby's trusted developer registry is the /catalog JSON array. Ask its maintainer to add a listing with this shape; there is no public submission API:
{
"id": "my-game",
"title": "My Game",
"manifest_url": "https://my-game.example/arcade/manifest.json",
"artwork": "https://my-game.example/discovery/cover.png",
"attract": "https://my-game.example/discovery/trailer.webm",
"screenshots": []
}
attract (trailer) is optional; discovery media URLs are HTTPS. The registry holds the stable manifest URL and discovery media. Your game owns its release manifest and payload files. Subsequent releases update that stable manifest, not Cubby's registry or executable. Browsing does not fetch the install manifest.
Understand the launcher boundary
Downloads and updates are free. The desktop test account starts with 10 local tokens; one token is charged per successful launch, not per game purchase or minute played. There is no timer. Do not implement charging inside the game. The browser demo is free and does not simulate native wallet enforcement. There are no real-money payments, creator payouts or cloud accounts yet.
Cubby verifies every file, stages a complete release and activates updates only outside gameplay. Existing ZIP schema 1 releases remain supported. New schema 2 file releases require Cubby Arcade desktop 0.3.0 or newer. A child's existing 0.2.0 executable must be replaced once to gain the new installer.
Before handing off
Test a fresh offline install, keyboard/controller input, pause/resume, return to library, save/restart and an update from a prior version. Verify all payload URLs use direct HTTPS (no redirects), and that uploaded byte sizes/hashes match. Physical controller and target-device performance need real hardware testing.