@minit-games/sdk
v1.7.0
Published
Official SDK for building Minit Games HTML5 mini-games
Readme
@minit-games/sdk
Official SDK for building Minit Games HTML5 mini-games. Provides the game lifecycle API, configuration helpers, UI components (tutorial overlays, feedback text, flying rewards, header bars), and background utilities.
Install
npm install @minit-games/sdkUsage
Core entry point
import { initializeSDK, getConfigValue, reportResult, loadingDone } from '@minit-games/sdk';
// Bootstrap the SDK at startup. Accepts an optional config for
// background and meta-tag injection (see API overview below).
initializeSDK();
// Read URL-param config (passed by the app). Returns a string (or
// undefined if the key is missing and no default is supplied) —
// coerce with Number(...) / parseInt(...) for numeric mods.
const difficulty = getConfigValue('difficulty', 'normal');
// Signal that assets are loaded and the game is ready to be shown.
// Until this is called, the Minit app keeps a loading state on top
// of the WebView — call it as soon as the first interactive frame
// is ready.
loadingDone();
// At game end, report the result. The Minit app immediately overlays
// its own result screen on top of the WebView, so the game loses
// focus — do NOT render an in-game "result submitted" confirmation,
// and stop driving updates after this call.
reportResult(1500, { flavorText: 'Great run!' });Game lifecycle
The host (Minit app or web player) wraps the game in a controlled lifecycle. Three SDK calls drive it:
initializeSDK(config?)— call once at startup to bootstrap the SDK and set up backward-compat shims. Cheap and synchronous. The optionalconfigarg can apply a background (config.background) and inject meta tags (config.metaTags: true).loadingDone()— call once when the game is interactive (assets loaded, first frame ready). Until this fires, the app keeps a loading state on top of the WebView; the player sees the loader, not your game. Calling it more than once is a no-op.reportResult(result, options?)— call once when the game ends. The host immediately overlays its own result screen, takes focus away from the WebView, and prepares to tear it down. Do not render any "submitted" confirmation in-game, and stop scheduling animations / audio / network calls after the call.
The flavorText option is a short caption rendered beneath the score on the host's result screen, and is also surfaced in the activity feed where friends see this player's results. Use it for context ('Beat the expert!', '3 turns to spare') — not for confirmation copy.
UI entry point
import { showTutorial, hideTutorial, showPositiveFeedback, createHeaderBar, spawnReward } from '@minit-games/sdk/ui';
// Tutorial hint
showTutorial('Tap to jump!', 'center');
// ... on first player action:
hideTutorial();
// Feedback pop-up
showPositiveFeedback('Combo x3!');
// Header bar with score and turns panels
const header = createHeaderBar({ y: 60, padding: 40 });
const score = header.addPanel({ label: 'Score', value: 0, align: 'right', style: { valueColor: '#f7931e' } });
const turns = header.addPanel({ label: 'Turns', value: 10 });
// Animate a reward flying to the score panel
score.flyToPanel({
start: { x: 200, y: 400 },
visual: '⭐',
onArrive: () => score.setValue(Number(score.getValue()) + 100, { animate: true })
});API overview
@minit-games/sdk (core)
| Export | Description |
|--------|-------------|
| initializeSDK(config?) | Initialize the SDK; sets up background and backward-compat shims |
| loadingDone() | Signal to the app that the game is ready to be shown |
| reportResult(result, options?) | Submit the final game result |
| getUserData() | Read the player's persistent userData string (see Persistent user data) |
| getConfigValue(key, default?) | Read a URL-param config value injected by the app |
| getConfig() | Get all URL-param config values as a plain object |
| seededRandom() | Deterministic random number (seeded from ?seed= param) |
| patchSeed(seed) | Override the random seed at runtime |
| addBackground(options?) | Apply a styled background to the game container |
| applyMetaTags() | Inject charset + viewport meta tags |
Legacy aliases
For backward compatibility with games written against earlier versions, the old Drop-prefixed names are exported as aliases: reportDropResult, getDropConfigValue, getDropConfig, initializeDropSDK, addDropBackground, applyDropMetaTags, getDropEnvironment, and the types DropBackground/DropResultOptions/DropEnvironment.
Using with AI assistants
Chat-based AI assistants (Claude, ChatGPT, Gemini, and others) can scaffold a complete Minit game project, but the output is typically source code — it needs a build step before it can be uploaded. Once your game is working in the AI's preview, give it this prompt:
The game is ready. Please run `npm run build` and give me a ZIP whose root is the contents of the `dist/` folder — `index.html` should be at the top of the ZIP, not inside a `dist/` subfolder.That ZIP is what you upload to the Creator Console. For a full walkthrough — including a Google AI Studio callout and what to do if the upload is rejected — see docs/ai-assistants.md.
Persistent user data
Each player has a single string slot stored per creator — shared across all of your games. The host (app) owns serialisation and transport; the SDK reads window.minit.userData as a plain string | undefined and the string value is forwarded unchanged (no JSON parse, no normalization). Use it to persist save data, settings, high scores, or any other per-player state (encode multiple values into a single string if needed).
Reading
import { getUserData } from '@minit-games/sdk';
const savedState = getUserData(); // string | undefined- Returns
undefinedwhen no value is stored for this player or when running outside the host app. - Returns
""when the stored value is the empty string — distinct fromundefined.
Local userData testing
During npm run dev, you can seed getUserData via a URL param — no app host required:
?userData=tutorialPlayed%3DtruegetUserData() will return 'tutorialPlayed=true'.
URL-param values apply only when the host has not injected window.minit.userData (i.e. the property is undefined or null). Any host-injected string (including "") wins over the URL param — URL params are a local-dev convenience only.
userDatais a reserved URL-param key. It is stripped fromgetConfig()andgetConfigValue(), sogetConfigValue('userData')always returnsundefined(or its default). Read userData exclusively viagetUserData().
Writing
Pass a string as userData in reportResult:
import { reportResult } from '@minit-games/sdk';
// Persist a plain string
reportResult(score, { userData: 'tutorialDone' });
// Encode multiple values into one string
const state = JSON.stringify({ level: 3, highScore: 1500 });
reportResult(score, { userData: state });Omitting userData (or not passing options) leaves the stored value unchanged. An empty string "" is a valid value and will overwrite any previously stored data.
Limits
- 1 KB (1024 UTF-8 bytes) maximum. Writes that exceed this limit are rejected and the existing value is left unchanged.
@minit-games/sdk/ui
| Export | Description |
|--------|-------------|
| showTutorial(text, options?) | Display a non-blocking tutorial hint overlay |
| hideTutorial() | Hide the current tutorial hint |
| isTutorialVisible() | Check if a tutorial hint is showing |
| showFeedback(text, variant?, duration?) | Show a temporary feedback pop-up ("positive", "neutral", "negative") |
| showPositiveFeedback(text, duration?) | Convenience wrapper — green variant |
| showNeutralFeedback(text, duration?) | Convenience wrapper — orange variant |
| showNegativeFeedback(text, duration?) | Convenience wrapper — red variant |
| preloadFeedbackFont() | Preload the feedback font to avoid flash |
| spawnReward(options) | Animate a single reward icon from start → target |
| spawnRewards(count, options, staggerMs?) | Animate multiple reward icons with staggered timing |
| createHeaderBar(config?) | Create a header bar for displaying game stats |
| getHeaderBar() | Get the current header bar instance |
Fonts and assets
Game assets must be self-contained
Minit games run sandboxed — the game WebView has no external network access at runtime. All assets (images, audio, fonts, etc.) must ship inside the game ZIP. Any <link> to fonts.googleapis.com or any other external URL will fail silently when the game plays inside the app.
If your build does reference Google Fonts links, the Minit publish pipeline will attempt to inline the font data automatically at publish time. This is a best-effort safety net — do not rely on it. The correct approach is to bundle font files (woff2) inside your project and reference them with relative-path @font-face rules:
@font-face {
font-family: 'MyFont';
src: url('./fonts/myfont.woff2') format('woff2');
font-weight: 400;
}After building, confirm that the font file appears in dist/ alongside index.html.
SDK UI fonts are built in
The SDK's own UI components (header panel, feedback text) bundle their fonts as base64-inlined woff2 — no network requests are made and they work fully offline. The bundled families are:
| Module | Font | Weight |
|--------|------|--------|
| @minit-games/sdk/ui — createHeaderBar | Lato | 400, 700 |
| @minit-games/sdk/ui — showFeedback / preloadFeedbackFont | Bowlby One SC | 400 |
Both families are latin subset. Their SIL OFL license texts ship in the licenses/ directory (included in the npm package).
Bundle-size impact
The font data is tree-shaken per module — games pay only for what they import:
| Component | Adds to bundle |
|-----------|---------------|
| createHeaderBar (Lato 400 + 700) | ~37 KB base64 (~27.5 KB woff2) |
| showFeedback / preloadFeedbackFont (Bowlby One SC 400) | ~26 KB base64 (~19.4 KB woff2) |
| Neither | 0 KB |
Games that use neither createHeaderBar nor any feedback function pay no overhead. This per-module elimination applies when the game is built with a tree-shaking bundler (Vite, Rollup, esbuild, webpack); unbundled ESM consumers load whatever modules they import.
License
MIT — see LICENSE.
