Building Games
UbuntuPlay games are signed ZIP files that run in any modern mobile browser. Write them in plain HTML, CSS, and JavaScript, record learning events, and distribute them through the Marketplace.
Game Structure
A minimal game is a ZIP containing an index.html entry point:
my-maths-game/
index.html ← the platform's entry point for your game
style.css
game.js
assets/
sounds/
images/
The platform serves index.html from the classroom server (marketplace demos preview it in a sandboxed iframe). Your game communicates with the platform via the window.UbuntuAnalytics global, plus window.UbuntuAI and window.UbuntuI18n for AI and translations.
The Analytics API
Include the platform script and record learning events with UbuntuAnalytics.track(eventType, gameId, metadata). Events queue locally (offline-safe) and flush to the classroom server automatically. Always guard access — the global is undefined when running outside the platform:
<script src="/analytics.js"></script>
<script>
const track = (type, meta) =>
window.UbuntuAnalytics?.track(type, 'my-maths-game', meta);
track('game_start');
track('quiz_correct', { subject: 'Maths', grade: '5' });
track('quiz_wrong', { subject: 'Maths', grade: '5' });
track('puzzle_complete', { puzzleId: 'level_1', stars: 3, timeSec: 42 });
track('level_complete', { level: 3 });
track('game_end', { score: 840 });
</script>
Event Reference
| Event Type | When to Fire | Notes |
|---|---|---|
game_start | Game loads and is ready | — |
game_end | Student exits or finishes | score in metadata |
puzzle_complete | Student solves a puzzle/question | timeSec, stars in metadata |
quiz_correct | Correct answer submitted | Feeds rolling accuracy + adaptive difficulty |
quiz_wrong | Incorrect answer submitted | Feeds rolling accuracy + adaptive difficulty |
level_complete | Level/zone/chapter finished | Drives marketplace demo caps |
Set metadata.subject so teacher and parent analytics attribute your game to the right subject. Use a stable attemptId in metadata for score submissions so retries deduplicate.
Student Context
Games never receive student identity — privacy by design. The analytics client resolves the student's session token itself and the server attributes events to an anonymous pseudonym. What your game can read:
// Rolling quiz accuracy for your game (0-100)
const acc = window.UbuntuAnalytics?.getRollingAccuracy('my-maths-game');
// AI-recommended difficulty from that accuracy
const level = await window.UbuntuAI?.getRecommendedDifficulty(acc, 'Maths');
// 'easy' | 'medium' | 'hard'
Testing Locally
Open index.html directly in a browser. The globals won't exist outside the platform, so optional-chained calls safely do nothing. For richer local testing, add a mock:
if (!window.UbuntuAnalytics) {
window.UbuntuAnalytics = {
track: (type, game, meta) => console.log('[analytics mock]', type, game, meta),
getRollingAccuracy: () => 75,
flush: async () => {},
};
}
Manifest Format
The Hub signs a manifest describing your game files. Pass it to POST /hub/api/dev/sign:
{
"type": "game_add",
"version": "1.0.0",
"gameId": "my-maths-game",
"name": "My Maths Game",
"icon": "🧮",
"files": [
{ "src": "index.html", "dest": "games/my-maths-game/index.html" },
{ "src": "game.js", "dest": "games/my-maths-game/game.js" },
{ "src": "style.css", "dest": "games/my-maths-game/style.css" }
]
}
Signing and Distributing
ZIP your game folder:
zip -r my-game.zip my-maths-game/Go to Dev Portal → Sign a ZIP or call
POST /hub/api/dev/sign.The hub signs the manifest with its private Ed25519 key and returns
manifest.json.Add
manifest.jsonto your ZIP root — this is the distributable game file.Submit the signed ZIP to the Marketplace for review.
Marketplace Submission
After signing, set marketplace metadata (name, description, category, grades, price) from the Dev Portal. Approved games appear in the hub catalogue and can be installed by any school on a supported plan.