Files
cinny/docs/handoff/features/avatar-metadata/HANDOFF.md
Max Litruv Boonzaayer e058165830 feat: upgrade toolchain and soften sync recovery after network blips
Bump Vite 8, matrix-js-sdk, and related deps; fix immer/vanilla-extract imports for new majors. Replace blocking sync error dialog with background recovery on wake/offline, and disable Vite auto-open in dev. Add feature handoff documentation index.
2026-07-09 01:55:09 +10:00

93 lines
2.9 KiB
Markdown

# Avatar metadata — handoff
## Summary
Paarrot embeds profile accent metadata **inside image files** (PNG, JPEG, WebP, GIF) so avatar colors, banners, gradients, and border colors travel with the MXC upload. Other Paarrot clients read this metadata to theme profile UI without extra Matrix account data fields.
## User-facing behavior
- **Settings → Account → Profile**: pick accent color (and related styling) applied to avatar image on save
- Profile viewers extract color/banner from avatar HTTP URL for themed headers
- Works across image formats users commonly upload
## Architecture
```
Profile settings UI
→ embedMetadata / embedColor (imageMetadata.ts)
→ format-specific: pngMetadata, jpegMetadata, webpMetadata, gifMetadata
→ upload to Matrix
Other clients / Profile.tsx
→ extractMetadataFromImage(fetch avatar)
→ apply CSS variables / banner URL
```
## Key files
| Path | Role |
|------|------|
| `cinny/src/app/utils/imageMetadata.ts` | Unified embed/extract API |
| `cinny/src/app/utils/pngMetadata.ts` | PNG tEXt chunks |
| `cinny/src/app/utils/jpegMetadata.ts` | JPEG XMP APP1 |
| `cinny/src/app/utils/webpMetadata.ts` | WebP XMP |
| `cinny/src/app/utils/gifMetadata.ts` | GIF application extension |
| `cinny/src/app/features/settings/account/Profile.tsx` | Settings UI + upload pipeline |
## Data model
Metadata keys (embedded in binary image, not Matrix):
| Key | Format | Notes |
|-----|--------|-------|
| `paarrot:color` | All | Accent color hex |
| `paarrot:banner` | PNG (+ unified API) | Banner image URL |
| `paarrot:borderColor` | PNG | Border accent |
| `paarrot:gradient` | PNG | Gradient spec |
XMP namespace: `http://paarrot.app/ns/1.0/`
## Dependencies
- Browser `ArrayBuffer` / `Uint8Array` parsing
- No server-side processing — client-only before upload
## Integration points
- **Profile display**: user profile cards read metadata from avatar URL
- **Image upload flow**: must re-encode image with metadata before `uploadContent`
## Testing
### Manual
1. Set profile color in settings; save avatar.
2. Download avatar MXC; verify metadata with hex dump or Paarrot on second account.
3. Repeat for PNG, JPEG, WebP, GIF uploads.
4. Remove color; verify strip functions work.
### Automated
- None — good candidate for unit tests on chunk parsers
## Known issues & gotchas
- Metadata stripped if user uploads through non-Paarrot client
- Large images: re-encoding memory cost on mobile
- Console logging in `pngMetadata.ts` (`extractColorFromPNG`) — noisy in prod
- Federation: only Paarrot-aware clients interpret metadata
## Future work
- Unit tests per format parser
- Fallback to account data if metadata missing
- Document binary spec in standalone spec doc
## Related docs
- None
## Add your extra things here
- Entry points: `extractPaarrotMetadata`, `embedPaarrotMetadata`, `embedPaarrotColor` in `imageMetadata.ts`
- Profile comment: "Stored in avatar image metadata, visible to other Paarrot users"