Photos, avatars, thumbnails, the mascot — and what each looks like when it fails.
Part of the Konjo design language. The laws in the spine apply here unless this chapter contradicts them.
Chrome carries no imagery. No photographic headers, no textured backgrounds, no image behind a nav bar. This was a deliberate calibration decision and it has a practical reason: the hero block has to work for a dojo that has never uploaded a picture, and most of them never will. A design that only looks good with photography is a design that looks broken for your first hundred customers.
Imagery appears in exactly four places: user content, avatars, event and dojo pages, and onboarding.
The failure case is the design
Every image in Konjo is remote, and remote means slow, missing, or 404. Decide what the absence looks like before the presence, because the absence is what a new dojo sees.
| Loading | Missing / failed | |
|---|---|---|
| Avatar | The initials fallback — never a spinner | The initials fallback, permanently |
| Thumbnail | surface.tag block at the final aspect ratio |
Same block with an inline glyph, no error text |
| Event / dojo photo | Reserved space at the final ratio | The section renders without it; nothing collapses |
Reserve the space at the final aspect ratio before the image arrives. Content that jumps when a picture loads is the most common way a list feels cheap, and it is entirely avoidable.
Use CachedImage rather than a bare Image, and
MediaThumbnail for anything in a grid or
feed — it already carries the radius, the ratio and the play overlay.
Avatars
Avatar is the only way a person is pictured.
- Sizes are fixed: 32 in a row and in the header, 88 on a profile. The header's carries a 1px hairline ring so it separates from whatever it sits on.
- Circular, always. A squared avatar reads as a logo.
- The fallback is initials on a flat fill, not a silhouette glyph. A generic person icon
makes eleven students look like the same student; "AT" does not. The fill is
surface.mutedwith a 1pxborder.subtlering andtext.secondaryinitials — named here because "a flat fill" was the whole specification and the next person to build an avatar somewhere new would have picked one. - Never tint an avatar by belt. Rank is carried by the belt dot beside it. Two encodings of the same fact is one too many, and a coloured ring around a photo fights the photo.
User photos and video
- Posts and coaching clips keep their own aspect ratio, capped so one tall image cannot own the screen.
- Video routes to Mux, never to Storage — see the
video pipeline. A video thumbnail is a
MediaThumbnailwith the play overlay; it never autoplays in a feed. - All uploads go through the upload queue, never Storage directly from a screen.
Text on a photograph
The short version: don't. If you must —
- A scrim between the photo and the text, dark enough that the text clears 4.5:1 against the lightest pixel it covers, not the average.
- The text must still be legible if the image fails to load, which means the scrim is a solid-enough fill on its own.
- Never
accent.redor any red on a photograph. Red is a role; on top of an unpredictable background it is just a colour that vanishes.
This is why the hero block is a solid surface carrying type, never a photograph.
The mascot
The Konjo ninja is the brand's mark and its mascot: one character, silent, always a black
belt (Kata interview). Canon, construction and the
pose list are in the ninja prompt pack; the vector masters are
in assets/brand/ninja/, and the app renders the PNGs that
scripts/brand/icons.mjs generates from them.
Where the ninja may appear:
- Onboarding and the auth screens, inline with the wordmark in
KonjoWordmark. - Marketing, emails and social.
- Empty states and error states, in the pose that matches the moment: point for "start here", seiza for nothing today, oops for something that failed.
- Celebrations and milestones: promotion for a belt, jump for a streak or badge.
Where it never appears:
- Chrome: tab bars, headers, navigation. The screen title does that job.
- Billing, waivers, safety flags and anything with legal or money consequences. Those moments are serious; a cartoon undercuts them.
- As a speaker. The ninja is silent: no speech bubbles, no first-person lines, no copy written "in its voice". The words on the screen stay in the app's plain voice.
- Recoloured, redrawn by hand, or holding a weapon.
In an empty or error state the ninja accompanies the message and the one way in; it never replaces them. A screen that shows the ninja and no action is still an empty state with no way in.
Never
- A stock photo of martial arts. Konjo shows this dojo or it shows type.
- A gradient standing in for an image.
- An image that is load-bearing for comprehension with no text alternative.
- A decorative image without
accessibilityElementsHidden— see accessibility. - Text baked into an image. It cannot scale, cannot be read aloud, and cannot be translated.