Skip to content

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

jsonc
{
  "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

FieldRequiredDescription
nameyesDisplay name shown in the library, the options panel, and the Workshop.
versionyesThe bundle version, for example 1.0.0. Bump it when you publish an update.
authoryesYour name or handle.
descriptionnoFree text shown under the name in the library and the options panel.
thumbnailnoPath to a thumbnail image, relative to the bundle root. Used in the library and Workshop.
tagsnoDiscovery tags applied when the bundle is published. Browsers can filter by them. See tags and mature.
maturenoWhen 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.
ignorenoGlob patterns for files to leave out when the bundle is packaged and published. See ignore.
permissionsyesThe capabilities the bundle requests. See Permissions.
contentyesThe surfaces the bundle can show. See content.
optionsnoThe 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).

jsonc
{ "name": "main", "entrypoint": "index.html", "type": "overlay",
  "width": 320, "height": 200, "condition": "$.options.mode == 'wave'" }
FieldRequiredDescription
nameyesA unique name for this surface within the bundle.
entrypointyesPath to the file to load, relative to the bundle root. See Entry point types.
typeyesoverlay or fullscreen. See Surface types.
widthnoInitial width in pixels. Only used for type: overlay.
heightnoInitial height in pixels. Only used for type: overlay.
minWidthnoSmallest width the overlay can be resized to, in pixels. type: overlay.
maxWidthnoLargest width the overlay can be resized to, in pixels. type: overlay.
minHeightnoSmallest height the overlay can be resized to, in pixels. type: overlay.
maxHeightnoLargest height the overlay can be resized to, in pixels. type: overlay.
replicatenotype: fullscreen only. When true, the surface is drawn on every display instead of just one. See Surface types.
conditionnoAn 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 entrypoint ends in .html or .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 entrypoint is 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. width and height set the initial box size; the bundle can resize itself at runtime with DesktopOverlaysAPI.size.set() if it has the sdk.size permission. minWidth/maxWidth/minHeight/maxHeight bound that resizing.
  • fullscreen: a surface that covers the whole display, for visualizers or wallpapers. width and height are ignored. Set replicate: true to 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_modules or *.map, matches at any depth, like a .gitignore rule.

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 permissions entry with an unknown scope.
  • A network.* permission with no value.
  • A permission with an empty reason.

See Permissions for the permission rules and Conditions for the condition language used by content, options, and choices.