lib/speakers.ts now has an image field on Speaker — a portrait per person, which is what the speaker block and performer.image actually want.
Alongside it, withEventAvatar falls back to the event's speaker_avatar when an event has exactly one speaker and that speaker has no registry image. That fallback exists only so the three events that already carry a banner portrait show one without any new uploads. It is restricted to single-speaker events because speaker_avatar is keyed by event slug, so on a panel it identifies nobody.
To close this
- Move the three existing portraits to per-speaker keys:
https://images.cppserbia.org/speakers/{key}.png
events/2026-05-27-Cpp-for-Combinatorial-Optimization.md → luka-matijevic
events/2026-06-25-Least-Frequently-Used-Cache.md → sergei-blinov
events/2026-07-22-The-Story-of-Cpp.md → no speaker: (documentary screening); decide whether it needs one at all
- Add
image: to those registry entries.
- Delete
withEventAvatar and its tests, and drop speaker_avatar from EventHeader in lib/events-server.ts.
- Consider having
scripts/upload-speaker-avatar.ts write the registry entry instead of event frontmatter, so /banner-avatar feeds both the banner and the page.
speaker_avatar itself stays — the banner generator uses it as the featured photo for that event.
lib/speakers.tsnow has animagefield onSpeaker— a portrait per person, which is what the speaker block andperformer.imageactually want.Alongside it,
withEventAvatarfalls back to the event'sspeaker_avatarwhen an event has exactly one speaker and that speaker has no registry image. That fallback exists only so the three events that already carry a banner portrait show one without any new uploads. It is restricted to single-speaker events becausespeaker_avataris keyed by event slug, so on a panel it identifies nobody.To close this
https://images.cppserbia.org/speakers/{key}.pngevents/2026-05-27-Cpp-for-Combinatorial-Optimization.md→luka-matijevicevents/2026-06-25-Least-Frequently-Used-Cache.md→sergei-blinovevents/2026-07-22-The-Story-of-Cpp.md→ nospeaker:(documentary screening); decide whether it needs one at allimage:to those registry entries.withEventAvatarand its tests, and dropspeaker_avatarfromEventHeaderinlib/events-server.ts.scripts/upload-speaker-avatar.tswrite the registry entry instead of event frontmatter, so/banner-avatarfeeds both the banner and the page.speaker_avataritself stays — the banner generator uses it as the featured photo for that event.