Docs / Content
Gallery & images
How and why mustr handles images the way it does — R2 storage, edge caching, per-album audiences, and upload limits.
Every image in mustr — avatars, medal art, event banners, gallery photos — is stored the same way, and understanding that mechanism explains a lot of behavior you'll notice elsewhere (why uploads have size limits, why images load instantly on a second view, why an SVG upload gets rejected).
Where images live
Uploads go to R2, Cloudflare's object storage, not the database. When you upload, the file is stored under a category (avatars, medals, ranks, events, pages, branding, gallery, …) with a content-addressed key — a name derived from the file itself, never reused, so two different uploads can never collide or overwrite each other.
Why only PNG, JPEG, GIF, and WebP
SVG uploads are deliberately rejected. An SVG can contain a <script> tag, and if it were served from mustr's own domain and opened directly, that script would run with the site's own permissions — a classic stored-XSS vector. Raster formats (PNG/JPEG/GIF/WebP) can't do that, so the upload endpoint only accepts them. It's a small restriction that closes a real hole.
Upload size limits
- Most categories (avatars, medals, ranks, events, page images, branding) are capped at 1 MB — these are insignia and small graphics, not photographs.
- Gallery photos get a higher ceiling of 6 MB, since they're real photography. In practice the gallery admin downscales images in your browser before uploading (full copy at ≤2560px, plus a 640px thumbnail, both WebP), so a typical photo upload is much smaller than the cap. Animated GIFs upload untouched, since re-encoding would keep only the first frame.
Why images load fast
Images are served from /media/<key>, a path that's deliberately outside the API layer so it can be cached hard at Cloudflare's edge — once an image has been requested once from a given edge location, later requests for it don't touch storage at all. Combined with the size caps and lazy-loading on the roster, this is what keeps image traffic essentially free even as a community grows into the thousands of members.
Replacing or deleting an image (a new avatar, a re-uploaded medal icon) automatically deletes the old file from storage in the background, so nothing orphaned accumulates and eats into your free-tier allowance for no reason.
The Gallery module
Admin → Content → Gallery manages albums. Each album carries its own audience — public, members, or a specific role — checked on every request, so a members-only album never leaks through a direct link or an anonymous page view. Deleting the role an album is gated to closes the album rather than opening it, so a data mistake never accidentally widens access.
An album holds photos (uploaded, downscaled as above) and videos — but videos are always embedded from YouTube or Twitch, never self-hosted, so there's no video-storage bill and no bandwidth cost, ever.
Ordering albums and photos uses explicit up/down buttons rather than drag-and-drop, on purpose — it stays usable on a phone, with a keyboard, and mid-upload, when a drag gesture would be awkward.