Component icons and project banners
TL;DR
- A component carries an icon; a project carries an avatar and a banner. A backend has no presentation of its own, and a solution entry inherits the project's.
- Upload is not storage: an avatar is re-encoded to 512 × 512 WebP and a banner to 1920 × 480 WebP, center-cropped to that aspect first. Author at the exact output size or the crop decides your composition for you.
- Accepted inputs are JPEG, PNG and WebP, decided by reading the bytes. Avatars cap at 5 MiB, banners at 10 MiB, and neither may exceed 6000 px on a side.
ppl component update --icon ./icon.pngandppl project update <id> --avatar @./icon.png --banner @./cover.pngupload and bind in one step.- Assets are served publicly. Nothing confidential belongs in one.
Where presentation lives
| Entity | Icon / avatar | Banner | Notes |
|---|---|---|---|
| Component | yes | no | Set from icon.png at creation, or with --icon later. |
| Project | yes | yes | The git repository for a backend; the card everyone browses. |
| Backend | inherited | inherited | A working tree carries no presentation of its own. |
| Solution | inherited | inherited | Copied from the project when published, and kept in step afterwards. |
| Application | no | no | Applications are addressed by name, not by card. |
What the platform does to an upload
Every asset passes through one path: decode, dimension check, center crop to the target aspect, scale, re-encode as lossy WebP at quality 80.
| Kind | Stored as | Aspect | Accepts | Caps |
|---|---|---|---|---|
| Avatar / icon | 512 × 512 WebP | 1:1 | JPEG, PNG, WebP | 5 MiB, 6000 px per side |
| Banner | 1920 × 480 WebP | 4:1 | JPEG, PNG, WebP | 10 MiB, 6000 px per side |
Transparency survives the re-encode, so a rounded-corner icon on a transparent background stays that way. The format is derived from the bytes rather than from the file name or the declared content type — an SVG must be rasterized before it can be uploaded.
Designing for the crop
The crop is centered and happens before the scale, which makes aspect ratio the load-bearing decision:
- A 16:9 frame cropped to 4:1 keeps 44% of its height. Screenshots make poor banners.
- A portrait photograph cropped to 1:1 loses its sides.
- An image smaller than the output is upscaled, and quality-80 WebP does not hide that.
An icon is read at roughly 48 px in a catalog row, so it wants one silhouette, two or three flat colors and thick strokes — no text, no hairlines. Banner content belongs inside the middle 60%, because surfaces overlay the display name on it. Flat vector art survives the re-encode cleanly; photographs and long smooth gradients band.
Setting them
ppl component update --icon ./icon.pngppl project update <project_id> --avatar @./icon.png --banner @./cover.png
The @ prefix uploads a local file. A bare value binds an asset reference that already exists, which is how several projects share one image.
A component picks up a sibling icon.png automatically at creation, and on a later update only while it still carries the default placeholder. After a real icon is set, changing it means naming --icon explicitly — a re-run of the directory sync will not overwrite it.
Related
- Release semantics — the component directory layout
icon.pngbelongs to. - Components — the component primitive.
- Solutions — what a published solution card shows.