Skip to main content

Static Assets

Verse supports four types of visual assets for artworks: images, videos, SVGs, and iframes (interactive/generative content). Each type has a different URL structure and rendering strategy.

Quick Start — Displaying an Asset

The baseUrl returned by the API is a template, not a ready-to-use URL. Replace {{SIZE}} and {{FORMAT}} before use:

// Turn a baseUrl template into a displayable image URL (works in any framework)
function resolveImageUrl(baseUrl, width = "w640", format = "webp") {
return baseUrl.replace("{{SIZE}}", width).replace("{{FORMAT}}", format);
}

// Example
const imageUrl = resolveImageUrl(cover.baseUrl);
// "https://verse.works/content/w640/artwork@webp"

Which field to use depends on the asset type:

Asset typeDisplay as image (thumbnail)Display natively
ImageAssetbaseUrl — replace {{SIZE}} and {{FORMAT}}Same as thumbnail
VideoAssetpreviewImageUrl — replace {{SIZE}} and {{FORMAT}}baseUrl — direct video URL, use in <video src>
SVGAssetpreviewImageUrl — replace {{SIZE}} and {{FORMAT}}baseUrl — use with size = "source" and no format
IFrameAssetpreviewImageUrl — replace {{SIZE}} and {{FORMAT}}iframeUrl — load in an <iframe src>
Common pitfall

If you see literal {{SIZE}} or {{FORMAT}} in your browser's network tab, the placeholders were not replaced. Every image baseUrl and previewImageUrl must be resolved before use.

Asset Types

Every artwork has a cover field that resolves to one of four GraphQL types:

TypePurposeKey fields
ImageAssetStatic or animated imagesbaseUrl, isGif, width, height, aspectRatio
VideoAssetNative video filesbaseUrl, previewImageUrl, previewAspectRatio
SVGAssetVector artworkbaseUrl, previewImageUrl, previewAspectRatio
IFrameAssetInteractive / generative contentbaseUrl, iframeUrl, previewImageUrl, aspectRatio

All types share id, caption, and mimeType. ImageAsset and VideoAsset also carry fileSize.

URL Construction — The Template System

The backend returns template URLs with two placeholders:

https://verse.works/content/{{SIZE}}/artwork@{{FORMAT}}
PlaceholderReplaced withExample
{{SIZE}}A width token or named sizew320, w640, w1400, w3840, source
{{FORMAT}}An image formatwebp, jpeg, png, gif, avif

Resolving a Template URL

Replace both placeholders to get a usable URL:

// Standard image — serve as WebP at 640px wide
const url = baseUrl.replace("{{SIZE}}", "w640").replace("{{FORMAT}}", "webp");
// → "https://verse.works/content/w640/artwork@webp"

// Source file — strip the format segment entirely
const originalUrl = baseUrl.replace("{{SIZE}}", "source").replace("@{{FORMAT}}", "");
// → "https://verse.works/content/source/artwork"

When you don't want a specific format (SVGs, original GIFs), remove the @{{FORMAT}} segment entirely.

Available Sizes

From the GraphQL ImageSizes enum:

THUMBNAIL | MEDIUM | FULLSCREEN
W80 | W160 | W320 | W480 | W640 | W980 | W1400 | W2400 | W3840

Plus special string values "source" (original file) and "sq1200" (1200px square crop).

Available Formats

From the GraphQL ImageFormats enum:

JPEG | WEBP | PNG | GIF | AVIF

Default format is WebP. Recommended format selection:

AssetContextFormat to use
Regular imageAnywebp (default)
GIF imageAnimated display (artwork page)gif (preserves animation)
GIF imageStatic thumbnailjpeg (faster than GIF-to-WebP conversion)
SVGAnyStrip @{{FORMAT}} — serve as original

Responsive Images

To serve responsive images (e.g. in an <img srcset>), generate multiple URLs at different widths:

const widths = [320, 640, 980, 1400];
const srcset = widths
.map(w => `${baseUrl.replace("{{SIZE}}", `w${w}`).replace("{{FORMAT}}", "webp")} ${w}w`)
.join(", ");

Video Rendering

Videos (VideoAsset) use a direct URL — no template placeholders:

<video autoplay loop muted playsinline preload="auto">
<source src="{cover.baseUrl}" type="video/mp4" />
</video>
  • baseUrl points directly to the video file
  • For thumbnails, use previewImageUrl (this is a template URL — resolve it like any image)

IFrame Rendering

IFrame assets (IFrameAsset) represent interactive or generative content. They can be displayed in two ways:

Live Mode

Render the interactive content in an iframe:

<iframe src="{cover.iframeUrl}" loading="lazy"></iframe>
tip

Use loading="lazy" to defer loading until the iframe is near the viewport. Consider using location.replace() instead of setting src to avoid polluting browser back/forward history.

Static Preview

Display the previewImageUrl as a regular image (resolve the template as usual). This is useful for thumbnails, grids, and contexts where interactive content is not needed.

GLB (3D Models)

If the iframeUrl ends in .glb, the content is a 3D model. On verse.works, these are routed through a dedicated viewer. For your own integration, you can use any glTF/GLB viewer library (e.g. <model-viewer>).

Some artworks support a high-resolution variant via query parameters appended to the iframeUrl.

SVG Rendering

SVGs are always served at original size with no format conversion:

const svgUrl = baseUrl.replace("{{SIZE}}", "source").replace("@{{FORMAT}}", "");

Image Preview / Fullscreen

When displaying assets in a fullscreen or preview context, each type renders differently:

  • ImageAsset — Full-resolution image. For GIFs, use the original format to preserve animation.
  • SVGAsset — Source-size image with no format conversion.
  • VideoAsset — Native <video> with aspect ratio preserved.
  • IFrameAsset<iframe> with aspect ratio preserved.

GraphQL Fragment

A recommended fragment for fetching all asset fields needed for rendering:

fragment AllArtworkCoverFormats on Artwork {
cover {
... on ImageAsset {
id, isGif, width, height, baseUrl, aspectRatio, caption, mimeType, fileSize
}
... on VideoAsset {
id, width, height, baseUrl, caption, previewAspectRatio, previewImageUrl,
mimeType, fileSize
}
... on SVGAsset {
id, baseUrl, caption, previewAspectRatio, previewImageUrl, mimeType, fileSize
}
... on IFrameAsset {
id, baseUrl, caption, previewImageUrl, iframeUrl, aspectRatio
}
}
}

Troubleshooting

Images are broken / return 404:

  • Check your browser's network tab. If the request URL contains literal {{SIZE}} or {{FORMAT}}, the placeholders were not replaced. Apply the substitution from the Quick Start section.

Image loads but is the wrong size:

  • Make sure you're using a valid size token. Valid values: w80, w160, w320, w480, w640, w980, w1400, w2400, w3840, source, thumbnail, medium, fullscreen, sq1200.

Video won't play:

  • VideoAsset.baseUrl is a direct URL (no placeholders). Use it in a <video> or <source> element. Don't apply {{SIZE}}/{{FORMAT}} substitution to video URLs.

Thumbnail is blank for a video/iframe/SVG:

  • For non-image asset types, use previewImageUrl (not baseUrl) to display a still thumbnail. See the Quick Start table.