Manifest ReferenceAssets

Assets

The Assets catalog — registering images, audio, video, subtitles, vectors, JSON, and plugin payloads with variants and localized resolution.

The optional assets section is the manifest's media registry. Every image, audio file, video, subtitle track, vector graphic, JSON blob, or plugin payload is registered once in the catalog under a stable ID, then referenced everywhere else by that ID (layer assetId, meta.cover, audio tracks, extras, preload hints).

Assets has three optional properties: base, catalog, and — since schema 1.5 — folders.

assets.base — base URLs

Optional per-category base URLs. All properties are absolute Uris: mediaBase, imageBase, audioBase, videoBase, sfxBase, thumbsBase, pluginsBase.

Variant src values may then be relative paths resolved against the matching base — keeping catalogs short and letting you swap CDNs by changing one line:

{
  "assets": {
    "base": {
      "imageBase": "https://cdn.example.com/comic/images/",
      "audioBase": "https://cdn.example.com/comic/audio/"
    }
  }
}

Resolving relative URLs

src, poster.src, character images.*, extras url / thumbnail and every other asset reference may be absolute or relative. Consumers resolve a relative reference in this order:

  1. assets.base.<category>Base for the asset's category (imageBase, audioBase, videoBase, pluginsBase; vector assets use imageBase),
  2. assets.base.mediaBase,
  3. the URL the manifest document itself was loaded from — the same rule a browser applies to relative links in an HTML page.

Absolute URLs (including data: and blob:) are used as-is. A directory holding the manifest next to its asset files is therefore a complete, playable bundle without any assets.base — this is exactly what a PanelWave work archive unzips to. Presigned or otherwise per-object URLs cannot share a base and stay absolute.

Catalog items

catalog is an array of typed items discriminated by category. All items share the AssetCommon base and add a variants array (always minItems: 1). Unknown properties are rejected.

Shared properties (AssetCommon)

PropertyTypeRequiredDescription
idIdentifierYesCatalog ID referenced by layers, tracks, covers, extras
localeLocaleCode—Marks the whole asset as locale-specific
altLocalizedString—Alternative text (accessibility)
captionLocalizedString—Caption text
transcriptLocalizedString—Transcript for audio/video (accessibility)
durationMsinteger ≥ 0—Media duration in milliseconds
sha256string—Content hash, pattern ^[A-Fa-f0-9]{64}$
tagsstring[]—Free-form tags
folderIdsIdentifier[]—Since schema 1.5: ids of assets.folders entries this asset is filed under (n:m, unique)

Item types by category

categorySchema defVariant typeExtra properties
"image"AssetCatalogItemImageImageVariant—
"audio"AssetCatalogItemAudioAudioVariantrole: ambient | music | voiceover | sfx | ui | none
"video"AssetCatalogItemVideoVideoVariantposter: VideoPoster (schema 1.1+)
"subtitle"AssetCatalogItemSubtitleSubtitleVariant—
"vector"AssetCatalogItemVectorVectorVariant—
"json"AssetCatalogItemJsonJsonVariant—
"pluginPayload"AssetCatalogItemPluginPayloadJsonVariant—

assets.folders — authoring folder tree (schema 1.5+)

Optional array of AssetFolder objects mirroring the authoring tool's asset-library folder structure, so it survives transfers between authoring systems (e.g. the CMS's work archives). Rendering consumers may ignore this block — it carries no presentation semantics.

PropertyTypeRequiredDescription
idIdentifierYesFolder id referenced by asset folderIds
namestring (min length 1)YesDisplay name
parentIdIdentifier—Parent folder for nesting; absent = top level
orderinteger ≥ 0—Sort position among siblings

Assets point at folders (not the other way around) via folderIds on the catalog entry; one asset may be filed in several folders.

Variant types

Variants are alternative encodings/resolutions of the same asset. Consumers pick the best variant for the device, format, and locale.

ImageVariant

PropertyTypeRequiredConstraintsDescription
srcstringYes—URL or path (relative to the category base)
mimestringYespattern ^image/e.g. image/avif, image/jpeg
wintegerYes≥ 1Intrinsic width in pixels
hintegerYes≥ 1Intrinsic height in pixels
densitynumber—0.5–4Device pixel ratio this variant targets

AudioVariant

PropertyTypeRequiredConstraintsDescription
srcstringYes—URL or path
mimestringYespattern ^audio/e.g. audio/mpeg, audio/ogg
bitrateKbpsinteger—≥ 8Bitrate
channelsinteger—1–6Channel count
sampleRateHzinteger—≥ 8000Sample rate
loopboolean—default falseVariant is loop-safe
localeLocaleCode——Locale-specific recording (e.g. voiceover)

VideoVariant

PropertyTypeRequiredConstraintsDescription
srcstringYes—URL or path
mimestringYespattern ^(video/|application/vnd\.apple\.mpegurl)e.g. video/mp4, or HLS playlists
wintegerYes≥ 16Width in pixels
hintegerYes≥ 16Height in pixels
fpsnumber—≥ 1Frame rate
codecstring——e.g. h264
streamingboolean—default falseVariant is a streaming manifest (HLS)
localeLocaleCode——Locale-specific variant
directionstring—forward | reverse, default forwardSchema 1.1+. reverse marks a pre-rendered, time-reversed encode (typically without audio) used for smooth pingpong playback; the player falls back to frame-stepping when no reverse variant exists. See Video

VideoPoster (schema 1.1+)

Poster/preview frame on a video catalog item, shown before playback starts (click-to-play, reduced-motion presentations):

PropertyTypeRequiredConstraints
srcstringYes—
mimestring—pattern ^image/
w / hinteger—≥ 1

SubtitleVariant

PropertyTypeRequiredConstraints
srcstringYes—
mimestringYestext/vtt | application/x-subrip
localeLocaleCodeYes—

VectorVariant

PropertyTypeRequiredConstraints
srcstringYes—
mimestringYesimage/svg+xml | application/pdf

JsonVariant

Used by both json and pluginPayload items:

PropertyTypeRequiredConstraints
srcstringYes—
mimestringYespattern ^application/json$

Example

{
  "assets": {
    "base": {
      "imageBase": "https://cdn.example.com/comic/images/",
      "videoBase": "https://cdn.example.com/comic/video/"
    },
    "catalog": [
      {
        "id": "img-alley",
        "category": "image",
        "alt": { "en-US": "Dark city alley in the rain" },
        "variants": [
          { "src": "alley-2048.avif", "mime": "image/avif", "w": 2048, "h": 1536, "density": 2 },
          { "src": "alley-1024.jpg", "mime": "image/jpeg", "w": 1024, "h": 768, "density": 1 }
        ]
      },
      {
        "id": "sfx-rain",
        "category": "audio",
        "role": "sfx",
        "variants": [
          { "src": "https://cdn.example.com/comic/audio/rain-loop.mp3", "mime": "audio/mpeg", "loop": true }
        ]
      },
      {
        "id": "vid-pendulum",
        "category": "video",
        "durationMs": 3000,
        "alt": { "en-US": "Pendulum swing, forward/backward" },
        "variants": [
          { "src": "pendulum-1280.mp4", "mime": "video/mp4", "w": 1280, "h": 720, "fps": 30, "codec": "h264", "direction": "forward" },
          { "src": "pendulum-1280-reverse.mp4", "mime": "video/mp4", "w": 1280, "h": 720, "fps": 30, "codec": "h264", "direction": "reverse" }
        ],
        "poster": { "src": "pendulum-poster.jpg", "mime": "image/jpeg", "w": 1280, "h": 720 }
      },
      {
        "id": "sub-intro",
        "category": "subtitle",
        "variants": [
          { "src": "https://cdn.example.com/comic/subs/intro.en-US.vtt", "mime": "text/vtt", "locale": "en-US" },
          { "src": "https://cdn.example.com/comic/subs/intro.de-DE.vtt", "mime": "text/vtt", "locale": "de-DE" }
        ]
      }
    ]
  }
}

Localized asset resolution

Localization can happen at three levels, from coarse to fine:

  1. Item level — AssetCommon.locale marks an entire catalog entry as belonging to one locale (e.g. a lettered artwork per language). Publish one item per locale and resolve by ID + locale.
  2. Variant level — AudioVariant, VideoVariant, and SubtitleVariant carry their own locale, so one catalog entry can hold all language versions. Consumers pick the variant whose locale best matches the reader's, walking the fallback chain to meta.default_locale.
  3. Reference level — the general AssetRef form ({ "assetId": "…", "variant": "…", "locale": "…" }) can pin a specific variant/locale at the point of use. See Layers.

Text-level localization (alt, caption, transcript) uses LocalizedString as everywhere else. The overall fallback algorithm is described in Localization.

Schema validation does not check that assetId references resolve to catalog entries, or that src URLs exist. The CLI warns when a manifest has panels but no assets section at all — see Validation.