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, notembeddedAssets - use
runtimeKeyfor app-side lookup - set
subcategoryfor normal asset categories - omit
subcategoryforCUSTOM - unchanged
ownedAssetsreuse the existing asset revision on republish - changed
ownedAssetscreate 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 publishinitializes an app upload session, uploads the app bundle and owned assets, then finalizes the session- direct
POST /creators/:creator/apps/:name/versionsuploads 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 asdist/index.htmlEXTERNAL: 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-packListing 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