Pandacap: Part 1
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
![[community profile]](https://www.dreamwidth.org/img/silk/identity/community.png)
Pandacap
This has been my hobby project for the better part of the past
year, and it's something I've been wanting to make a series of
blog posts about for a while. Pandacap is my personal Swiss Army
knife web app; it hosts my art gallery and microblog and collects
incoming posts and notifications across five different sites and
protocols.
The code for
Pandacap is open-source (AGPL v3). I don't imagine it will
be that useful to many people; trying to ask a non-Microsoft-stack
developer to make tweaks to it would be like asking me to
contribute to, well, anything in Python. (Plus, the code itself is
not very robust, and not at all scalable.) But I've made
some very deliberate decisions in the UI of this app, with an eye
towards my own psychological well-being. The context collapse of
traditional social media kept me away from it for years, and this
app (and one of its predecessors, Artwork Inbox)
is the reason I can follow artists on Bluesky and Mastodon without
giving up in frustration. I'm hoping that someday, these design
principles could be useful to other people who find themselves in
the same situation.
The application itself is split into a set of public pages - the
subject of this post - and a collection of features that are only
accessible once I've logged in with my own Microsoft account. I'll
cover authorization, crossposting, inboxes and notifications, and
ActivityPub support in future blog posts, and perhaps some of the
internal architecture and design decisions as well.
The main design considerations of Pandacap are:
- Keep idle resource usage and cost as low as possible
- Uses Azure PaaS offerings (App Service, Cosmos DB,
Functions) instead of virtual machines
- Absent any manual intervention from myself, the site going down is better than the cost going up
- No infinite scrolling - limit the number of posts shown per click
- Different kinds of posts are not mixed together in the inbox
- Artwork and text posts are separated
- Original posts and boosts (retweets) are separated
- Within each page, posts are grouped by their author (or by
who boosted them)
- All content shown to the public is put there manually by the instance owner
- Posts, favorites, and follows are public
- Followers and comments are hidden
By the way, I'm writing this blog post here instead of on
Pandacap itself for two reasons: it's not particularly applicable
to the persona I use for my art, and since Pandacap is something I
host on my own Azure account, it's hard to say how long I'll keep
it around, and I'm quite confident that Dreamwidth will outlast
it.
Profile
This is the root page of my Pandacap instance at https://pandacap.azurewebsites.net.
(Normally I'd feel a bit weird about posting a link, unprompted,
to what's essentially my own art profile, but it's clearly visible
in the screenshot, so it'd be odd not to mention it here.) Those
of you who have done ASP.NET development will probably recognize
its roots in the default Bootstrap template.
First of all, note the navigation links at the top: Gallery,
Journals, and Status Updates. Unlike general-purpose blogs and
microblogs, Pandacap splits local posts into these three
categories.
Artwork posts in the gallery have a title and an attached image;
journal entries lack the title but are expected to have a longer
body / description; status updates can have an image (or not) but
always lack a title.
(Another separate post type exists - an "addressed post" - which
is used for ActivityPub replies; these text-only posts are public
but are not listed on the profile.)
Under my avatar and username, you'll see a handful of links.
First is the ActivityPub card, with a handle which allows Mastodon
and Pixelfed users to follow the Pandacap server directly. You can
also see ActivityPub users I'm following, ActivityPub posts I've
added to my "favorites" (this is sent to other servers as a
"like"), and Lemmy communities I've bookmarked.
Next to the ActivityPub card, you'll see Atom and RSS links:
feeds are made available for each post type, or combined into a
single feed. (These URLs are actually the same as the ones in the
header, just with a format= parameter). If you want to
see what these feeds look like, try loading them up in Edge and
then switching to Internet Explorer mode.
Finally, there are cards for my DeviantArt, Bluesky, and Weasyl
accounts. For each of these, there's a link to my profile there
(Bluesky uses the DID, just because I haven't yet implemented
Bluesky handle lookup). There are also links to who I'm following
and my favorites list on each of those sites (the Bluesky web
app's "liked" list is part of the profile page; it doesn't have
its own URL).
Below that ersatz linktree is a search box, and then a set of my
most recent artwork posts - eight of them, with thumbnails. The
five most recent status updates are shown as well; in this case,
the two with images first, and then the three without. Journal
entries would be shown too, if there were any recent enough;
however, for non-artwork posts, Pandacap won't show it on the
homepage if it considers it "too old". (It'll still be in the
appropriate list and on the feed, though.)
Gallery
My gallery page looks something like this (but with my drawings,
of course). Just like on the main page, image posts are shown as
thumbnails with their titles as captions. This screenshot also
shows the "next page" button. When setting up my Pandacap
instance, I imported my DeviantArt post history going back more
than a decade, so you could be clicking "next page" for quite a
while.
Journals / Status Updates
The Status Updates and Journals pages are almost identical - the
main difference is that journal entries have a title, while status
updates lack one. (Journals also cannot have images, at least not
right now.)
Note that status updates are grouped first by whether they have
an image attached, then sorted by date. This isn't something I
feel strongly about - it's more an artifact of this page sharing
most of its display code with the favorites and gallery sections.
View Post
Finally, there's the page for the post itself. Each element of
the post is laid out in order:
- My avatar, username, and handle
- The post title (if any)
- The timestamp
- The attached image (if any), maximum 640x640
- The post body / description (if any)
- The tags for the post (if any)
- "View on" buttons for the accounts this post has been crossposted to
Note that this page's URL is also the ActivityPub ID for this
post - you can copy and paste it into Mastodon, Pixelfed, or some
other ActivityPub server and find it that way.