The game convention
A Gamentic game is an ordinary self-contained HTML5 game plus a handful of marker comments. Follow them and the game gains a live Inspector, server-injected art and audio, export and remixing. Ignore them and it is still a game — the convention is purely additive.
Your AI reads the canonical version of this from the server with get_convention, which
is required before writing any game. This page is the human summary — useful for reviewing
what the AI produced, or for writing a game by hand.
The marker comments
Five globals carry everything the platform can see or change. Each is declared once in
game.html, and each assignment ends with an exact marker comment. The server finds
those markers by text to inject generated art, audio and models; the Inspector finds
GAME_CONFIG to build the tuning panel.
| Global | Marker | Holds |
|---|---|---|
window.GAME_CONFIG | // __GI_CONFIG__ | Every tunable number, colour, toggle and level layout |
window.GAME_ASSETS | // __GI_ASSETS__ | Generated images, by name |
window.GAME_AUDIO | // __GI_AUDIO__ | Generated music, speech and sound effects |
window.GAME_MODELS | // __GI_MODELS__ | Generated 3D models and rigs |
window.GAME_DATA | // __GI_DATA__ | Content the AI edits without touching code — dialogue, levels, item tables |
1. One config object
Everything tunable goes in a single global, and the right-hand side must be valid JSON: double-quoted keys, no trailing comma, no functions, comments or expressions.
window.GAME_CONFIG = {
"gravity": 0.6,
"playerSpeed": 4.5,
"enemyColor": "#ff4757",
"hardMode": false,
"level": [[1,1,0],[0,1,0],[0,1,1]]
}; // __GI_CONFIG__
Never write a defensive fallback on a marker line. This is the single most common mistake:
window.GAME_ASSETS = {}; // __GI_ASSETS__ correct
window.GAME_ASSETS = window.GAME_ASSETS || {}; // __GI_ASSETS__ breaks injection
With ||, ??, a ternary or Object.assign(...) the
right-hand side stops being JSON, so the server can no longer rewrite the block — and
generated art simply never lands. Nothing errors. The guard is not needed anyway: these globals
are defined right here, exactly once.
Each marker may appear only once in the whole file, and the game loop must read
window.GAME_CONFIG directly every frame. Copy a value into a local at start-up and a
panel edit will not take effect until the next reload.
2. The harness
Five lines let the Inspector push edits into a running game. Copy them verbatim.
window.__GI_SET = function (patch) {
Object.assign(window.GAME_CONFIG, patch);
if (typeof window.__giOnChange === 'function') window.__giOnChange(patch);
};
console.log('__GI__' + JSON.stringify({ type: 'ready', config: window.GAME_CONFIG }));
Two optional hooks:
window.__giOnChange = (patch) => {...}— for derived state that is not re-read every frame, such as rebuilding an enemy pool after the count changes.window.__giOnAction = (key) => {...}— for panel buttons like restart or clear board.
3. The schema
The schema describes the panel. It is passed to create_game and is never inlined into
the game HTML, which is why editing a game in the Inspector cannot corrupt it.
{
"groups": [
{ "label": "Feel", "fields": [
{ "key": "gravity", "type": "float", "min": 0.1, "max": 2, "step": 0.05, "label": "Gravity" }
]},
{ "label": "Controls", "fields": [
{ "key": "restart", "type": "action", "label": "Restart" }
]}
]
}
| Type | Control | Needs |
|---|---|---|
int / float | Slider | min, max, step |
bool | Toggle | — |
enum | Dropdown | options |
color | Colour picker | value is #rrggbb |
string | Text field | — |
grid2d | Grid editor | rows, cols, palette; value is a 2D number array |
action | Button | fires __giOnAction(key) |
Every field except action needs a matching default in GAME_CONFIG.
Groups should mean something — Feel, Difficulty, Appearance, Controls — rather than one
undifferentiated lump. A game whose difficulty numbers are not exposed cannot be tuned by the
person playing it, which is most of the point.
4. A self-contained package
Nothing may load from another domain: no CDN script, no remote font, no external image, no
fetch() to the internet. Graphics are drawn on canvas, sound is synthesized with
WebAudio or injected as generated audio. This is not a house style — the sandboxes these
games run in block external resources outright.
Self-contained describes the package, not a single file. A game is a folder:
game.html the shell: markers, boot, <script src="src/..."> in load order
src/**.js your code, split by responsibility
media/** images and audio (the server puts them here)
Marker blocks and the harness stay in game.html. Move one into src/
and nothing errors — generated art and audio just quietly stop arriving, because the
server looks for those markers in game.html alone.
game.html must end with </html>; a truncated upload is rejected
rather than stored half-written. Export, remix and publishing to itch.io or Newgrounds all carry
src/ and media/ along with the shell.