World media (thumbnail, preview image, preview video)
Set a world's card artwork and the images + YouTube video that play in its detail carousel. Images upload through a presigned PUT; video is referenced from YouTube, not hosted.
Every world has a thumbnail (its card artwork across discovery) and an optional preview image plus an optional preview video that appear as extra slides in the world detail carousel.
The thumbnail is always the cover
Until a creator uploads one, a world's thumbnailUrl is a deterministic auto-generated
data:image/svg+xml placeholder — it is never null. Check hasCustomThumbnail to tell a real
upload from the placeholder; testing thumbnailUrl for null will always say "set".
The media slots
Prop
Type
Video is referenced, not uploaded
The preview slot accepts images only. video/mp4 and video/webm uploads are rejected with a
400. Use the YouTube endpoint below instead — YouTube handles transcoding, adaptive streaming,
moderation and bandwidth, and the world detail embeds it privacy-first via youtube-nocookie.
Uploading an image
Two steps, mirroring the build-upload flow. Both are owner-gated.
# 1. Presign. `kind` is "thumbnail" (default) or "preview".
curl -X POST "$API/api/v1/instant-worlds/$WORLD_ID/media/upload" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"contentType":"image/png","size":267583,"kind":"preview"}'
# → { "item": { "key": "...", "url": "<presigned PUT>", "contentType": "...", "cacheControl": "..." } }The presigned URL is bound to the exact contentType and byte size you declared — send the same
bytes you measured, or the PUT is rejected.
# 2. PUT the bytes straight to storage, then finalize with the key you were given.
curl -X PUT "$UPLOAD_URL" -H "Content-Type: image/png" --data-binary @preview.png
curl -X POST "$API/api/v1/instant-worlds/$WORLD_ID/media/finalize" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"key":"'"$KEY"'","kind":"preview"}'
# → the updated worldAccepted image types: image/png, image/jpeg, image/webp, image/gif, image/avif.
Your image is live immediately
Moderation runs asynchronously — you never wait on a verdict. If a scan later flags the image, the slot is cleared and the world falls back to its generated thumbnail.
Setting a preview video
Paste any normal YouTube link. It is normalised server-side to a video id and stored; nothing is downloaded or re-hosted.
curl -X POST "$API/api/v1/instant-worlds/$WORLD_ID/media/youtube" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"url":"https://www.youtube.com/watch?v=dQw4w9WgXcQ&t=30s"}'All of these resolve to the same id — extra params like &t= and &list= are discarded:
Prop
Type
Anything that is not a YouTube reference — another host, a javascript: URL, a malformed id — is
rejected with a 400. There is no best-effort fallback.
The world then carries both a raw id and a ready-made embed URL:
Prop
Type
Prefer previewYoutubeUrl over building your own
Embedding previewYoutubeUrl keeps you on the nocookie host and matches what the HELIX world detail
does. If you build your own player, load it on click rather than on page load — an eagerly
mounted YouTube iframe pulls ~1MB of player JS into your page's critical path.
Clearing a slot
# kind = thumbnail (reverts to the generated SVG) | preview | youtube
curl -X DELETE "$API/api/v1/instant-worlds/$WORLD_ID/media?kind=youtube" \
-H "Authorization: Bearer $TOKEN"Reading media back
Every world response carries the resolved URLs:
const world = await fetch(`${API}/api/v1/instant-worlds/${slug}`).then((r) => r.json());
world.item.thumbnailUrl; // always set (custom upload or generated SVG)
world.item.hasCustomThumbnail; // false → it's the generated placeholder
world.item.previewMediaUrl; // preview image, or null
world.item.previewYoutubeId; // video id, or null
world.item.previewYoutubeUrl; // nocookie embed URL, or nullImage URLs are served through the CDN's image transform, so they arrive already resized and in a modern format for the requesting browser.
How the carousel assembles slides
The world detail builds its carousel in this order, skipping anything unset and de-duplicating identical URLs:
- Thumbnail — always the cover, and the page's LCP image.
- Preview image — if set and different from the thumbnail.
- Screenshots — the gallery a creator arranges in the editor, in their order.
- Preview video — last, as a click-to-play slide.
A preview that duplicates the thumbnail is worse than no preview
The carousel de-duplicates identical URLs, but it cannot tell that two different URLs hold the same picture. Uploading a copy of your thumbnail as the preview gives players a carousel that shows the same image twice. Make the preview earn its slide: a different area, a different moment, something the cover doesn't already show.
Collectibles
Scarce, serialized universal items that trade peer-to-peer for LIX. How they differ from ordinary items, and how worlds use them.
Content rating & maturity
Every item and world declares a maturity rating. The platform gates discovery and access by it — and creators attest to it at publish time.