Today I'm announcing atp.pics, a teeny-tiny public utility service that makes it easy to get the avatar image for any Atmosphere identifier. It supports multiple identifier formats, image transformations, and global caching. You can use it anywhere you want to put a face to a name--whether your app is atproto integrated or not.
Most importantly, atp.pics supports trying multiple profile records--so if you don't have a Bluesky profile, it can still return your Tangled/Spark/other avatar image. Only Bluesky is supported at the moment, but I have issues for Tangled and Spark, and I would love suggestions for other profiles.
It's free to use. I don't intend for atp.pics to be all that fancy or formal, I just hope it solves a need for some and that folks find it useful.
How it works
- 1.
Your browser/app/service makes a request
GET /{identifier}, via fetch or an<img>tag - 2.
atp.pics resolves the user's PDS and attempts to get their
app.bsky.actor.profilerecord - 3.
On a miss, it tries to fetch another profile (e.g.
sh.tangled.actor.profile) until it finds a record with an avatar blob - 4.
Once a blob is found, the server applies any requested modifications to the image and stores the result in Tigris
- 5.
The atp.pics server responds with a 302 redirect to the transformed image in Tigris
- 6.
Your browser/app/service follows the redirect to receive the transformed image
As I write that out, I realize I'll want to call com.atproto.repo.describeRepo to flatten resolution time, so I'll write that fix in shortly.
Why atp.pics?
We could have Gravatar at home
This all started when asked about a gravatar for atproto, and I thought about how handy it would be to be able to grab my profile picture from a human-writable URL. That was the only Gravatar feature I ever used, personally.
I made a first iteration of that service, called silhouette, but it had far fewer features (and used probably the wrong redirect code) compared to atp.pics. The latter should be much more durable, but as with any early software, things might be a little rough.
What is the nature of our existence billion disparate profile records?
I keep emphasizing support for multiple profile lexicons, because it's a hot topic in the ecosystem at the moment. As mentions, it's difficult to explain to folks that accounts (profiles) across services are actually all the same account (DID/repo). As the ecosystem picks up pace, my take is that now is the right time to be trying and formulating recommendations for profile records.
This is a similarly bothersome issue as a developer. Anyone who wants to launch an atproto service usually decides between shipping their own profile lexicon or piggybacking off an existing one (typically app.bsky.actor.profile). Do you present them a bespoke profile, do you show them a profile that they're already familiar with, or do you base the former on the latter and allow changes to diverge? Does anybody know? It seems not.
This is top-of-mind as I work on microclimate, my voice channel-first social app. Inspired by Discord, microclimate provides a similar "server" abstraction--and I'd like to support per-server profiles, so I'm about to become neck-deep in this problem. atp.pics felt like a way to get my feet wet; a place to start inspecting all of the profiles out there to inspect their similarities, differences, pros and cons.
What's next?
In the near term, I'm going to add some more profile records to check for avatars, and implement that optimization I mentioned earlier. atp.pics is probably a ball of jagged, sharp edges, so if you choose to use it or adopt it for a project, please let me know if you run into any problems.
I'm considering adding a lexicon to let users determine their own profile resolution order, but... that mostly feels like a feature just for nerds like me who frequently type https://atp.pics/graham.systems into their browser. I'm not convinced it'll get all that much mileage. If you want a feature like that because your Spark avatar is so much cooler than your Bluesky avatar, make sure to let me know. Or maybe I should allow you to specify an actor profile in query params? Idk, I need to support more lexicons first before I think about that.
Ultimately, I think the atmosphere needs to give actor profiles the standard.site or lexicon.community treatment. I hope to chat with folks about this at --you can help me out by telling me your thoughts there, on Bluesky, or by submitting your service's profile lexicon so I have more food for thought.
Anyways... That's atp.pics. I hope you find it useful, if you need it!