Manifest reference
Every bundle has a manifest named desktop-overlays.config.json at the root of its folder. It holds the metadata, the capabilities the bundle requests, the surfaces it can show, and the controls in its settings panel.
Full example
{
"name": "Audio Waves",
"version": "1.0.0",
"author": "your-name",
"description": "An FFT visualizer",
"thumbnail": "thumb.png",
"tags": ["Audio", "Visualizer"],
"mature": false,
"ignore": ["node_modules", "src/**", "*.map"],
"permissions": [
{ "scope": "sdk.audio", "reason": "Visualizes sound with an FFT" },
{ "scope": "sdk.media", "reason": "Shows the playing track title" },
{ "scope": "sdk.size", "reason": "Resizes itself to fit its content" },
{ "scope": "network.http", "value": "https://api.example.com/*", "reason": "Fetches score data" }
],
"content": [
{ "name": "main", "entrypoint": "index.html", "type": "overlay",
"width": 320, "height": 200, "condition": "$.options.mode == 'wave'" },
{ "name": "full", "entrypoint": "full.html", "type": "fullscreen",
"condition": "$.app.fullscreen == true" }
],
"options": [
{ "key": "mode", "name": "Mode", "type": "input", "kind": "select",
"choices": [ { "label": "Wave", "value": "wave" },
{ "label": "Bars", "value": "bars" } ] }
]
}Top-level fields
| Field | Required | Description |
|---|---|---|
name | yes | Display name shown in the library, the options panel, and the Workshop. |
version | yes | The bundle version, for example 1.0.0. Bump it when you publish an update. |
author | yes | Your name or handle. |
description | no | Free text shown under the name in the library and the options panel. |
thumbnail | no | Path to a thumbnail image, relative to the bundle root. Used in the library and Workshop. |
tags | no | Discovery tags applied when the bundle is published. Browsers can filter by them. See tags and mature. |
mature | no | When true, the bundle is flagged as mature content on publish, so it is hidden from the Workshop browser unless the user opts in. See tags and mature. |
ignore | no | Glob patterns for files to leave out when the bundle is packaged and published. See ignore. |
permissions | yes | The capabilities the bundle requests. See Permissions. |
content | yes | The surfaces the bundle can show. See content. |
options | no | The controls in the settings panel. See Options. |
content
content is a list of surfaces the bundle can render. Most bundles have exactly one. When more than one is listed, dropping the bundle spawns one overlay per entry, so every surface appears at once. Each overlay is pinned to its entry and shows while that entry's condition holds; when the condition is false the overlay hides. This means you can ship several independent surfaces in one bundle, and you can also gate a surface with a condition so it only appears in certain states (for example a compact box and a fullscreen variant that swap as the app goes fullscreen).
{ "name": "main", "entrypoint": "index.html", "type": "overlay",
"width": 320, "height": 200, "condition": "$.options.mode == 'wave'" }| Field | Required | Description |
|---|---|---|
name | yes | A unique name for this surface within the bundle. |
entrypoint | yes | Path to the file to load, relative to the bundle root. See Entry point types. |
type | yes | overlay or fullscreen. See Surface types. |
width | no | Initial width in pixels. Only used for type: overlay. |
height | no | Initial height in pixels. Only used for type: overlay. |
minWidth | no | Smallest width the overlay can be resized to, in pixels. type: overlay. |
maxWidth | no | Largest width the overlay can be resized to, in pixels. type: overlay. |
minHeight | no | Smallest height the overlay can be resized to, in pixels. type: overlay. |
maxHeight | no | Largest height the overlay can be resized to, in pixels. type: overlay. |
replicate | no | type: fullscreen only. When true, the surface is drawn on every display instead of just one. See Surface types. |
condition | no | An expression that decides whether this surface is active. If omitted, the surface is always eligible. See Conditions. |
The size bounds clamp both editor drag-resize and DesktopOverlaysAPI.size.set(). Omit an edge to leave it unbounded.
Entry point types
- If
entrypointends in.htmlor.htm, it runs as a web page inside a sandboxed iframe. The SDK and the content security policy are injected for it. This is the normal case. - If
entrypointis a supported media file (img,gif,mp4,webm, and similar), it is drawn directly as an image or video, like a plain media overlay. The SDK is not available for media entry points.
Because both forms accept condition, type, width, and height, you can switch between an interactive surface and a static media surface based on state.
Surface types
overlay: a positionable, anchorable box. This is the normal overlay behavior.widthandheightset the initial box size; the bundle can resize itself at runtime withDesktopOverlaysAPI.size.set()if it has thesdk.sizepermission.minWidth/maxWidth/minHeight/maxHeightbound that resizing.fullscreen: a surface that covers the whole display, for visualizers or wallpapers.widthandheightare ignored. Setreplicate: trueto draw the surface on every display at once (like the cursor effects); each display gets its own instance of the surface, sized to that monitor.
tags and mature content
tags is a list of discovery tags. They are applied to the Workshop item when the bundle is published, and the in-app browser's filter sidebar matches against them. They are free-form, but the browser surfaces a curated set of presets:
Clock, Audio, Visualizer, Wallpaper, Pet, Sticker, System, Game, Anime, Minimal, Seasonal, Utility.
Using a preset tag lets your bundle show up when a browser filters by it. Selecting several tags in the browser is an OR match: an item is shown if it carries any one of them.
mature marks the bundle as mature content. On publish it adds Steam's mature content descriptor plus a reserved mature tag, so the item is hidden from the browser unless the user turns on the Mature content switch. Steam also applies the viewer's own mature-content preference server-side.
The ignore field
ignore is a list of glob patterns. When the app packages and publishes the bundle, any file that matches a pattern is left out. Use it to keep development files out of the published bundle: source folders, node_modules, build output, source maps, and so on.
*matches within a single path segment.**matches across path segments.?matches a single character.- A pattern with no slash, such as
node_modulesor*.map, matches at any depth, like a.gitignorerule.
desktop-overlays.config.json is always kept, even if a pattern would match it.
Validation
The manifest is validated before the bundle installs. These are rejected:
- A
permissionsentry with an unknownscope. - A
network.*permission with novalue. - A permission with an empty
reason.
See Permissions for the permission rules and Conditions for the condition language used by content, options, and choices.