feat(badges): host premium badge artwork in R2
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 33
- Forks
- 104
- Avg merge
- 12h 3m
- Merged PRs (30d)
- 10
Description
Summary
When premium badges (Lifetime Achievement, named awards, decade-anniversary commemoratives, year-stamped conference attendee marks) need elaborate illustration rather than a geometric glyph, host the artwork in R2 instead of bundling it. Keeps the bundle light and lets new artwork ship without a deploy.
Requirements
- Add a `badge-artwork` R2 prefix (or a dedicated bucket) alongside the existing `PROFILE_PHOTOS` binding in `wrangler.jsonc`.
- Convention: artwork keyed by `{tier}/{slug}.svg` (or `.webp` for raster). Public-readable via the bucket's `r2.dev` URL or a `BADGE_ARTWORK_PUBLIC_URL` var, mirroring the photos pattern.
- Optional `artworkUrl` field on the badge payload — when present, the renderer prefers it over the inline glyph; when absent, falls back to the existing `HexStamp` glyph for that kind.
- Badge component renders the artwork with the same hex frame + accent ring so the visual system stays cohesive whether artwork is bundled or fetched.
- Loading state: skeleton hex (matching the accent) while the artwork loads, fallback to inline glyph on fetch error.
- No artwork required for any badge in Phase 1 or Phase 2 — this is a Phase 3 prerequisite for the named-award badges and a prep step for any future commemoratives.
Context
Current visual system (`HexStamp.tsx`) draws geometric primitives inline as SVG paths. Total weight is a few KB and the inline approach lets us color glyphs via the accent palette using `currentColor`. Moving the existing glyphs to R2 would increase complexity (loading states, network round-trips) without meaningful bundle savings.
R2 is the right call only when artwork is large enough to matter (50–500 KB illustrations), photographic, animated, or year-stamped per-conference. Treat it as an opt-in path for prestige badges, not a wholesale migration.
Implementation Notes
- `R2Bucket` binding in `packages/api/wrangler.jsonc` follows the `PROFILE_PHOTOS` precedent. Add `BADGE_ARTWORK` and `BADGE_ARTWORK_PUBLIC_URL`.
- Upload pipeline can mirror the photo URL-import path in `packages/api/src/lib/storage.ts` once admin tooling exists. For now, a one-off bash script to upload commissioned artwork is fine.
- `BadgeItem` shape gains an optional `artworkUrl: string | null`. The renderer's hex-frame component checks it first, then falls back to the per-kind glyph.
- Cache headers: long max-age + content-hash in the filename so updates invalidate cleanly.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/api/wrangler.jsonc and compare the existing PROFILE_PHOTOS binding, then read packages/api/src/lib/storage.ts for the photo URL-import pattern. Next inspect HexStamp.tsx and the BadgeItem renderer path. Done means the opt-in artwork URL path, framed loading and error fallback, and R2 configuration are covered without changing existing inline glyph behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend, cloud, frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100