Reference documentation

Publishing Reference

Publishing ties local workspace content to the live Playdrop catalogue.

Updated April 6, 2026

Publishing Reference

Publishing ties local workspace content to the live Playdrop catalogue.

Use this page for:

  • catalogue.json
  • versioning and lifecycle
  • listing metadata
  • media guidance for icons, heroes, screenshots, and video

Catalogue JSON

catalogue.json is the local source of truth for publishable Playdrop content.

Top-level shape

json example

{
  "apps": [],
  "assets": [],
  "assetPacks": []
}

App example

json example

{
  "name": "my-app",
  "version": "1.0.0",
  "file": "dist/index.html",
  "type": "GAME",
  "displayName": "My App",
  "description": "One sentence about what the player does",
  "authMode": "OPTIONAL",
  "controllerMode": "SUPPORTED",
  "previewable": true,
  "achievements": [
    {
      "key": "first_finish",
      "displayName": "First Finish",
      "description": "Finish one run"
    }
  ],
  "leaderboards": [
    {
      "key": "fastest_lap",
      "displayName": "Fastest Lap",
      "scoreType": "TIME_MS",
      "sort": "ASC"
    }
  ]
}

App owned assets

Apps may register reusable catalogue assets directly inside the app entry with ownedAssets.

Use this when:

  • the game should load catalogue assets instead of bundling every file in ./assets/...
  • you want other creators or other apps to reuse the same assets
  • republishing the app should reuse unchanged asset revisions instead of creating duplicates

Example:

json example

{
  "name": "starter-kit-3d-platformer",
  "version": "1.1.0",
  "file": "dist/index.html",
  "type": "DEMO",
  "ownedAssets": [
    {
      "name": "starter-kit-3d-platformer-character",
      "runtimeKey": "character",
      "category": "MODEL_3D",
      "subcategory": "humanoid",
      "format": "GLB",
      "visibility": "PUBLIC",
      "files": {
        "primary": "assets/models/character.glb"
      }
    },
    {
      "name": "starter-kit-3d-platformer-level",
      "runtimeKey": "level",
      "category": "CUSTOM",
      "format": "CUSTOM",
      "assetSpec": "asset-spec:playdrop/level@1.0.0",
      "visibility": "PUBLIC",
      "files": {
        "primary": "assets/levels/level-1.json"
      }
    }
  ]
}

runtimeKey is the in-game lookup key. In the app runtime, resolve registered assets with:

ts example

const character = sdk.assets.resolveAppAsset('character');
const allAssets = sdk.assets.listAppAssets();

Rules:

  • use ownedAssets, not embeddedAssets
  • use runtimeKey for app-side lookup
  • set subcategory for normal asset categories
  • omit subcategory for CUSTOM
  • unchanged ownedAssets reuse the existing asset revision on republish
  • changed ownedAssets create a new asset revision
  • published runtime asset file URLs are stable public URLs so the game can load them through normal browser caching

App publishing is session-based.

  • playdrop project publish initializes an app upload session, uploads the app bundle and owned assets, then finalizes the session
  • direct POST /creators/:creator/apps/:name/versions uploads are no longer part of the supported client workflow

App hosting modes

Apps can either be hosted on Playdrop or hosted elsewhere.

  • HOSTED: the app files live in your Playdrop workspace and the app entry points at a local file such as dist/index.html
  • EXTERNAL: the game already lives at a public HTTPS URL and Playdrop stores the catalogue entry, listing metadata, and store media while launching the external game URL

If you provide externalUrl, Playdrop treats the app as EXTERNAL.

External app example

json example

{
  "name": "my-external-game",
  "version": "1.0.0",
  "type": "GAME",
  "displayName": "My External Game",
  "description": "Arcade game already hosted on our own site",
  "visibility": "PUBLIC",
  "hostingMode": "EXTERNAL",
  "externalUrl": "https://example.com/games/my-external-game/",
  "listing": {
    "icon": "listing/icon.png",
    "heroLandscape": "listing/hero-landscape.png",
    "screenshotsLandscape": [
      "listing/screenshots/landscape/1.png"
    ]
  }
}

Use HOSTED when Playdrop should publish the app files from your workspace. Use EXTERNAL when the game should stay hosted at its current public URL.

Asset example

json example

{
  "name": "sword-icon",
  "displayName": "Sword Icon",
  "description": "Inventory icon",
  "category": "IMAGE",
  "subcategory": "generic",
  "format": "PNG",
  "visibility": "PUBLIC",
  "files": {
    "primary": "assets/sword-icon.png",
    "preview": "assets/sword-icon-preview.png"
  }
}

Pack example

json example

{
  "name": "starter-pack",
  "version": "1.0.0",
  "displayName": "Starter Pack",
  "description": "Core starter assets",
  "visibility": "PUBLIC",
  "assets": [
    "asset:playdrop/sword-icon@r1",
    "asset:playdrop/shield-icon@r2"
  ]
}

Packs support the same ownedAssets contract for local assets, and unchanged owned assets are reused there too.

Validate and publish:

bash example

playdrop project validate .
playdrop project publish .

Versioning and Lifecycle

Playdrop content is versioned by object type:

  • apps use semantic versions such as 1.0.0
  • assets use revisions such as r1
  • packs use semantic versions such as 1.0.0

Use explicit versions when you need deterministic remixing, stable audit history, repeatable promotion, or controlled current-version changes.

Inspect versions:

bash example

playdrop versions browse playdrop/app/hangingout
playdrop versions browse playdrop/asset/sample-asset
playdrop versions browse playdrop/pack/starter-pack

Listing Metadata

Listing metadata is how creators explain catalogue content clearly.

At minimum, each listing should make these obvious:

  • what the content is
  • who it is for
  • what a player or creator can do with it
  • why the current version matters

Good:

text example

Topdown Drift
Arcade racing game where the player chains short drift boosts across compact tracks.

Weak:

text example

My Game
Cool game.

Media Guidelines

Use media to remove ambiguity from a listing quickly.

For apps:

  • icon: recognizable at small sizes
  • hero image: strongest high-level frame of the experience
  • screenshots: show actual gameplay or creator workflow
  • video: optional, but useful when motion or pacing matters

For assets and packs:

  • use previews that show the asset clearly
  • avoid unrelated decoration that hides what the content actually is
  • for packs, show the pack identity, not just one item without context