Gridponder DSL v0.5 — Theme & Controls Schema
Defines visual presentation and input bindings — colors, rendering, and gesture-to-action mapping — without affecting gameplay semantics.
Purpose
theme.json defines the visual presentation and input bindings for a game: colors, board rendering, avatar appearance, text styling, and gesture-to-action mapping. Theme data is non-normative — it does not affect gameplay semantics. Engine implementations may override or extend theme settings for their platform.
Input bindings live here (rather than in game.json) because the same game actions need different physical inputs on different platforms — swipes on mobile, arrow keys on desktop/web, d-pad on gamepad. The game declares what actions exist (in game.json); the theme declares how the player triggers them.
A game pack includes one theme.json alongside game.json. If omitted, the engine applies sensible defaults.
Top-Level Structure
{
"controls": { ... },
"coverImage": "assets/cover.png",
"primaryColor": "#4CAF50",
"backgroundColor": "#1A1A2E",
"boardStyle": { ... },
"textStyle": { ... },
"avatar": { ... }
}
Field Reference
| Field | Type | Required | Description |
|---|---|---|---|
controls |
object | no | Input bindings — gesture/key to action mapping. |
coverImage |
string | no | Path to cover art for the library screen. |
primaryColor |
string | no | Primary accent color (hex). |
backgroundColor |
string | no | Background color (hex). |
boardStyle |
object | no | Board rendering settings. |
textStyle |
object | no | Text rendering settings. |
avatar |
object | no | Avatar appearance settings. |
Controls
Maps platform inputs to abstract game actions. The engine uses these bindings as defaults; platforms may override them.
"controls": {
"gestureMap": [
{ "gesture": "swipe_cardinal", "action": "move", "paramMapping": { "direction": "swipe_direction" } },
{ "gesture": "swipe_diagonal", "action": "diagonal_swap", "paramMapping": { "direction": "swipe_direction" } },
{ "gesture": "tap_cell", "action": "tap_cell", "paramMapping": { "position": "tap_position" } },
{ "gesture": "button", "buttonId": "rotate_cw", "action": "rotate", "params": { "rotation": "clockwise" } }
]
}
| Field | Type | Required | Description |
|---|---|---|---|
gestureMap |
array | yes | List of input-to-action bindings. |
Each gesture mapping:
| Field | Type | Required | Description |
|---|---|---|---|
gesture |
string | yes | Input type: swipe_cardinal, swipe_diagonal, tap_cell, button. |
action |
string | yes | Action id to emit. Must match an entry in game.json actions. |
buttonId |
string | conditional | Required when gesture is button. UI control identifier. |
paramMapping |
object | no | Maps input parameters to action parameters dynamically. |
params |
object | no | Static parameters to include with the action. |
Platform behavior: On mobile, gestures are used directly. On web/desktop, the engine maps arrow keys to swipe_cardinal equivalents, and provides on-screen buttons for button-type actions. Games can provide platform-specific overrides (future extension).
Board Style
"boardStyle": {
"cellSize": 64,
"cellSpacing": 2,
"borderRadius": 4,
"gridLineColor": "#333333",
"showGridLines": true
}
| Field | Type | Default | Description |
|---|---|---|---|
cellSize |
integer | 64 |
Suggested cell size in logical pixels. |
cellSpacing |
integer | 2 |
Gap between cells. |
borderRadius |
integer | 4 |
Cell corner radius. |
gridLineColor |
string | "#333333" |
Grid line color (hex). |
showGridLines |
boolean | true |
Whether to show grid lines. |
Text Style
"textStyle": {
"fontFamily": "default",
"titleColor": "#FFFFFF",
"bodyColor": "#CCCCCC"
}
| Field | Type | Default | Description |
|---|---|---|---|
fontFamily |
string | "default" |
Font family name or "default" for platform font. |
titleColor |
string | "#FFFFFF" |
Title text color (hex). |
bodyColor |
string | "#CCCCCC" |
Body text color (hex). |
Avatar
The avatar section defines the character's appearance. It supports a simple single-sprite mode and a full sprite map for directional and animated avatars.
Simple mode
"avatar": {
"sprite": "assets/sprites/rabbit.png",
"visible": true
}
| Field | Type | Default | Description |
|---|---|---|---|
sprite |
string | (engine default) | Fallback sprite. Used when no sprite map is provided, or as default for missing states. |
visible |
boolean | true |
Whether avatar is rendered. Set to false for overlay-only games. |
Sprite map mode
For games with directional movement, the avatar should use a sprite map keyed by state and direction. States are emitted by systems during gameplay (e.g., avatar_navigation sets "moving", push_objects sets "pushing").
"avatar": {
"visible": true,
"sprites": {
"idle": {
"right": "assets/sprites/avatar/rabbit_looking_right.png",
"left": "assets/sprites/avatar/rabbit_looking_slightly_left.png",
"up": "assets/sprites/avatar/rabbit_idle_away_from_player.png",
"down": "assets/sprites/avatar/rabbit_idle_facing_player.png"
},
"moving": {
"right": {
"frames": ["assets/sprites/avatar/rabbit_walking_right_1.png", "assets/sprites/avatar/rabbit_walking_right_2.png"],
"duration": 400,
"mode": "loop"
},
"left": { "mirror": "right" },
"up": {
"frames": ["assets/sprites/avatar/rabbit_walking_up_1.png", "assets/sprites/avatar/rabbit_walking_up_2.png"],
"duration": 400,
"mode": "loop"
},
"down": {
"frames": ["assets/sprites/avatar/rabbit_walking_down_1.png", "assets/sprites/avatar/rabbit_walking_down_2.png"],
"duration": 400,
"mode": "loop"
}
},
"pushing": {
"right": {
"frames": ["assets/sprites/avatar/rabbit_push_start.png", "assets/sprites/avatar/rabbit_push_right_middle.png", "assets/sprites/avatar/rabbit_push_right_end.png"],
"duration": 300,
"mode": "once"
},
"left": { "mirror": "right" },
"up": { "mirror": "right" },
"down": { "mirror": "right" }
}
}
}
Sprite map structure
| Level | Key | Value |
|---|---|---|
| State | "idle", "moving", "pushing", or custom |
Direction map |
| Direction | "up", "down", "left", "right" |
Static sprite, animation, or mirror |
Direction values
Each direction entry is one of:
| Form | Description |
|---|---|
"path.png" |
Static sprite (string). |
{ "frames": [...], "duration": N, "mode": "..." } |
Animated sprite (same schema as entity animations). |
{ "mirror": "direction" } |
Reuse another direction's sprite/animation, horizontally flipped. Avoids duplicate assets. |
Resolution order
When the engine needs a sprite for state S and direction D:
- Look up
sprites[S][D] - If missing, fall back to
sprites["idle"][D] - If missing, fall back to
sprite(top-level fallback) - If missing, use engine default
Games without directional movement (e.g., slide_merge-only games) can use simple mode — no sprite map needed.
Complete Example
{
"controls": {
"gestureMap": [
{ "gesture": "swipe_cardinal", "action": "move", "paramMapping": { "direction": "swipe_direction" } }
]
},
"coverImage": "assets/cover.png",
"primaryColor": "#4CAF50",
"backgroundColor": "#1A1A2E",
"boardStyle": {
"cellSize": 64,
"cellSpacing": 2,
"showGridLines": true
},
"textStyle": {
"fontFamily": "default",
"titleColor": "#FFFFFF"
},
"avatar": {
"visible": true,
"sprites": {
"idle": {
"right": "assets/sprites/avatar/rabbit_looking_right.png",
"left": "assets/sprites/avatar/rabbit_looking_slightly_left.png",
"up": "assets/sprites/avatar/rabbit_idle_away_from_player.png",
"down": "assets/sprites/avatar/rabbit_idle_facing_player.png"
},
"moving": {
"right": {
"frames": ["assets/sprites/avatar/rabbit_walking_right_1.png", "assets/sprites/avatar/rabbit_walking_right_2.png"],
"duration": 400,
"mode": "loop"
},
"left": { "mirror": "right" },
"up": {
"frames": ["assets/sprites/avatar/rabbit_walking_up_1.png", "assets/sprites/avatar/rabbit_walking_up_2.png"],
"duration": 400,
"mode": "loop"
},
"down": {
"frames": ["assets/sprites/avatar/rabbit_walking_down_1.png", "assets/sprites/avatar/rabbit_walking_down_2.png"],
"duration": 400,
"mode": "loop"
}
},
"pushing": {
"right": {
"frames": ["assets/sprites/avatar/rabbit_push_start.png", "assets/sprites/avatar/rabbit_push_right_middle.png", "assets/sprites/avatar/rabbit_push_right_end.png"],
"duration": 300,
"mode": "once"
},
"left": { "mirror": "right" }
}
}
}
}