Brua

The AssetResponse

The JSON every SDK reads: the HTML picture model as data, with a field for each attribute, descriptor or media feature it maps to.

The contract is plain JSON, objects, strings, numbers and arrays, with no polymorphism, so Swift decodes it with synthesized Codable, Kotlin with kotlinx.serialization, .NET with System.Text.Json and the web with a plain type. Every field is named after the HTML attribute, srcset descriptor or CSS media feature it maps to. Optional fields are left out, never null. A field the contract gains later is ignored by older clients.

An example

Brua's own bridge, read from the edge with ?lang=en, trimmed to a few of its variants:

JSON
{
  "id": "bridge",
  "version": 1,
  "release": 3,
  "url": "https://cdn.brua.dev/assets/991ceed8-a70e-4a5f-b3d3-e0b6b3d93e44/bridge",
  "width": 640,
  "height": 400,
  "alt": "Brua, a bridge drawn as an arc over a line",
  "lang": "en",
  "variants": [
    { "type": "application/x-lottie+json", "prefersColorScheme": "light", "lang": "en", "url": ".../bridge/1/en-light.json" },
    { "type": "application/x-lottie+json", "prefersColorScheme": "dark", "lang": "en", "url": ".../bridge/1/en-dark.json" },
    { "type": "image/avif", "prefersColorScheme": "light", "prefersReducedMotion": "reduce", "lang": "en", "scale": 2, "url": ".../bridge/1/en-light-still@2x.avif" },
    { "type": "image/webp", "prefersColorScheme": "dark", "prefersReducedMotion": "reduce", "lang": "en", "scale": 2, "url": ".../bridge/1/en-dark-still@2x.webp" }
  ]
}

The fields

Field Standard Meaning
id The asset's id, as the backend passes it on
version The asset's version in this release
release The project's release this JSON comes from; on the edge only, not in the delivery API's response
url HTTP content negotiation The single URL: one URL that the edge resolves from the request, or from ?w= and the other overrides
width, height <img width height> The size the asset is designed for: scale 1 for fixed assets, the source's size for flexible ones. Also the aspect ratio of every variant
alt <img alt> Always present, in the language resolved from Accept-Language or ?lang=; "" only for decorative assets
lang <img lang>, BCP 47 The language of alt; absent when decorative
variants[].type IANA media type image/avif, image/webp, image/png, image/jpeg, image/svg+xml, application/x-lottie+json, application/x-rive
variants[].url The file, immutable under its versioned URL
variants[].prefersColorScheme CSS prefers-color-scheme light or dark; absent, the file fits both
variants[].prefersReducedMotion CSS prefers-reduced-motion reduce marks the still of an animation, also its loading placeholder
variants[].lang BCP 47 For assets with files per language; only the resolved language's variants are returned
variants[].scale srcset x A fixed asset's raster at that scale; 2 and 3 always, 1 when made
variants[].pixelWidth srcset w A flexible asset's raster at that width; a ladder of widths

A raster variant has scale or pixelWidth, never both. Thumbnails of a flexible asset are its smaller widths, not separate assets; an art-directed thumbnail is its own asset.

The selection rule

Given the variants and what the client renders (the media types it decodes, its color scheme, whether it reduces motion, its scale and the width it will show), the rule picks one variant. Every SDK and the edge run the same rule against the shared fixtures in the brua-web repository's fixtures/selection, so a change to it starts with a fixture.

Next