Game manifest#
A game describes itself in a unihub.manifest.json at the root of its folder, and the
Hub reads nothing else about it: change the manifest and submit a new version to update its
listing. package.json stays only to build the game. The JSON Schema
unihub.manifest.v1.json holds every
rule below; point $schema at it and editors autocomplete and explain each field.
unihub.manifest.json#
{
"$schema": "https://play.unikia.es/schema/unihub.manifest.v1.json",
"manifestVersion": 1,
"id": "heated-heist",
"title": "Heated Heist",
"version": "0.1.0",
"developers": ["cebun"],
"description": "Rob fictional estates while every sound brings more armed security.",
"tagline": "Get in. Get rich. Get out.",
"details": "Steal jewellery and money from rich people's fictional mansions...",
"genre": "Shooter",
"tags": ["Top-down shooter", "Heist", "Stealth", "Co-op", "Online co-op", "Arcade", "2D"],
"players": { "min": 1, "max": 2 },
"platforms": ["desktop", "mobile"],
"languages": ["en", "es"],
"color": "#f382cd",
"cover": "public/assets/menu-bg.webp",
"squareCover": "public/assets/square.webp",
"badge": "public/assets/badge.webp",
"path": "heist-game",
"achievements": "public/achievements.json",
"changelog": "CHANGELOG.md",
"sdk": "^1.4.0"
}
| Field | Required | Meaning |
|---|---|---|
manifestVersion |
yes | Always 1. |
id |
yes | The stable game id (game id): a-z, 0-9 and -, at most 40 characters. Never change it once published. |
title |
yes | The game's name in the Hub, at most 40 characters. |
version |
yes | Semver, shown in Game details. It wins over package.json's; uniplay validate warns when they differ. |
developers |
yes | 1 to 10 Hub nicknames of the people who make the game, shown as its Developers in Game details. Only they can submit it. |
description |
yes | One-line pitch shown under the title, at most 160 characters. |
tagline |
yes | A short slogan on the artwork, at most 60 characters; the Hub shows it in capitals. |
details |
no | Longer text for Game details, at most 600 characters. Defaults to description. |
genre |
yes | The one main genre, at most 24 characters, e.g. "Shooter", "Roguelite". Everything else goes in tags. |
tags |
no | Up to 12 more descriptors, each at most 24 characters, most important first: sub-genres, modes, setting, style (e.g. "Top-down shooter", "Co-op", "Pixel art", "2D"). Shown as written. |
players |
yes | How many can play. A number is exactly that many: 1 for single player, 2 for a game that always needs two. A range { "min": 1, "max": 4 } is a game playable solo or with up to four (co-op or versus). Shown as "1 player", "2 players" or "1–4 players". |
platforms |
no | Devices the game is made for: one or more of "desktop" (keyboard, mouse or controller) and "mobile" (touch screens). Shown as icons in the Hub. Defaults to ["desktop"]; list "mobile" only when the game is playable with touch alone. |
languages |
no | Languages the game can be played in, as BCP 47 codes such as "en", "es" or "pt-BR", the original language first. Game details lists them by name. Defaults to ["en"]. |
playthroughs |
no | Whether Game details offers Start a new game, which puts the player's saves aside as another playthrough they can switch back to. Set it to false for a game that keeps its own save slots (characters, save files), so players start over inside the game instead. Playthroughs already put aside stay listed. Defaults to true. |
fullscreen |
no | Whether the game asks to be played fullscreen, such as a first-person shooter. When it starts in Uniplay for desktop, the window goes fullscreen, unless the player turned that off in Settings → General, and comes back when they leave the game. On the site the game stays in the page. Defaults to false. |
coopAcrossVersions |
no | Whether buds on different versions of the game can play together. By default they can't: the game sees only the peers on its version, and the Hub offers the one behind an update before they join. Set it to true when versions stay compatible. Defaults to false. |
color |
no | Accent colour, #rrggbb. |
cover |
one of the two | Path to 16:9 key art, .webp, .png or .jpg (1600×900 .webp works best), for the game's page and the list view. The Hub shows it as is, without drawing the title over it, so include the logo in the art. |
squareCover |
one of the two | Path to 1:1 key art, .webp, .png or .jpg (1024×1024 .webp works best), for the grid view, with the logo in it too. A game needs cover, squareCover or both: without a square cover the grid crops the middle of the 16:9 one, and without a 16:9 cover the Hub fits the square one over a blurred copy of itself. |
badge |
no | Path to the game's platinum badge, .webp, .png or .jpg, 1:1 (a 256×256 .webp with a transparent background works best). Players see it greyed out on their profile and in Game details until they unlock every achievement. Without one, the Hub cuts a round badge from the cover. |
entry |
no | The built game's HTML file. Its folder is served at /<path>/. Defaults to dist/index.html. |
achievements |
no | Path to the game's achievements.json. |
changelog |
no | Path to the game's release notes, in the Keep a Changelog format. Translations sit next to it with a language tag before the extension (CHANGELOG.es.md, CHANGELOG.pt-BR.md); players see the one in their Hub language (or its language without the region), else this one. |
sdk |
no | The SDK range the game was built against, e.g. ^1.4.0. |
path |
no | URL folder the game's page is at, /<path>/. Defaults to the id. The game itself plays from its version's own address, /g/<id>/<version>/, so load its files by relative URLs (./assets/…), never /<path>/…. admin, api, assets, developers, g, healthz, library, licenses, policy, publisher, schema and uniplay are reserved, and the Hub may assign another one on review to avoid clashes. |
Every path is relative to the manifest and stays inside the game's folder. The order of the game list and which games the Store features are the Hub's choice.
The game package#
A game reaches the Hub as one zip: the game's own folder once built, with only what the
manifest names. npx -p @unikia/upe-cli uniplay pack writes it for you.
heated-heist.zip
├── unihub.manifest.json required
├── package.json required
├── dist/ required: the built game, entry at dist/index.html
├── public/assets/menu-bg.webp the cover, at the path the manifest names
├── public/assets/square.webp the square cover, likewise, if there is one
├── public/assets/badge.webp the platinum badge, likewise, if there is one
├── public/achievements.json optional, see achievements
└── CHANGELOG.md optional release notes (Keep a Changelog), CHANGELOG.es.md…
unihub.manifest.jsonandpackage.jsonare at the root of the zip, in no folder.- The built game is under the entry's folder (
dist/by default), and the covers, badge, achievements and changelog (with its translations) at the paths the manifest names. - At most 500 MB zipped, 1 GB unzipped and 5,000 files.
- No symbolic links, absolute paths,
..in paths,__MACOSX/or.DS_Store. - The entry's folder must work from any base path: the Hub serves it from
/<path>/, and may changepathon review. Build it with relative URLs (Vite:--base=./). - When published, the entry's folder is served under
/<path>/with the entry renamed togame.html, the achievements next to it asachievements.json, the cover at/uniplay/covers/<id>.<ext>, the square cover at/uniplay/covers/square/<id>.<ext>and the badge at/uniplay/badges/<id>.<ext>. The changelog is parsed into/uniplay/changelogs/<id>.json(releases newest first, each with its### Added,### Changed… sections;[Unreleased]shows as the latest changes), which Game details opens from the version; translations into<id>.<lang>.json(keep### Added… in English)./<path>/itself serves the Hub page, which opens the game in a frame (the Hub shell).game.htmlnext to the entry is reserved. uniplay validate [folder]checks a game's folder once it's built: the manifest against its schema,package.json, that every file the manifest names exists, that the cover is a 16:9 image, the square cover and badge 1:1 ones, and that the achievements pass their own schema. The Hub runs the same checks on every submission.
