- JavaScript 59.7%
- HTML 32%
- CSS 8.3%
| public | Added undocumented contentType filter to the /api/search endpoing for efficiency. | |
| .gitignore | Open Web Gallery - a masonry image gallery for open social platforms | |
| LICENSE | Open Web Gallery - a masonry image gallery for open social platforms | |
| README.md | Attempt to provide clearer instructions for getting started. | |
Open Web Gallery
A learning project exploring modern CSS, HTML, and JavaScript features by building a mosaic image gallery that displays photos from open web platforms.
The platforms that exist at the moment are Mastodon, BlueSky and Blacksky, Lemmy, PieFed, Vernissage, and Holos. Each platform has its own adapter that handles fetching and displaying content according to the platform's API and conventions.
How This Happened
On a cold, lazy Sunday afternoon, I thought it would be cool to create a gallery view of christmas decorations I found on mastodon.social. I was familiar with the search endpoints and the elasticsearch options like has:image -is:sensitive #christmas so I decided to build something.
Every Sunday, I would tweak a bit more of the CSS to get a better layout, add new features, and eventually add support for more platforms. It's been a fun way to learn by doing and scratch my own itch for a gallery view of open web content. Each week I would change my default gallery to a new hashtag or feed.
CSS brings me joy and despair in equal measure. I am in awe of CSS designers creating beautiful, functional layouts and I refuse to give up on learning it myself. This project is a testament to that stubbornness. I have no doubt there are many things I am doing wrong, but I hope it can be a fun example of what can be built with just HTML, CSS, and JavaScript.
Let's just say it got a little out of hand. From a single platform and a single file to...this. But it's done now!
For real this time. Until I build another adapter.
No promises.
Quick Start
Running Locally
# Clone the repository
git clone https://codeberg.org/box464/open-web-gallery.git
cd open-web-gallery
# Start a local server (required for fetch API)
python3 -m http.server 8000 -d public
# Open in browser
open http://localhost:8000
Configuration
Code Configuration
To set the default values for what appears in the gallery without URL parameters, edit the queryConfig and filterConfig objects in scripts/config.js. This is where you can set your default platform, instance, hashtag, and filter settings. The configuration page will override these defaults when you generate a URL with specific parameters.
const queryConfig = {
adapter: 'mastodon', // mastodon, bluesky, piefed, lemmy, vernissage, holos
tag: 'photography', // Hashtag to search (without #)
actor: null, // User/community to filter by
feed: null, // Custom feed ID (BlueSky, PieFed)
// ... filter settings
};
const filterConfig = {
excludeReposts: true,
excludeBots: true,
excludeSensitive: true,
excludeAiGenerated: true,
minFavouritesCount: 3,
minRepostsCount: 1,
// ... other filters
};
The easy way: Use the Configuration Page to build gallery URLs with a user-friendly form. Select your platform, instance, sources, and filters, then generate a shareable link.
You'll quickly find that adding more filters often means fewer or no results, especially on smaller instances. Start with broad settings and narrow down as needed.
The like and boost thresholds are a good way to filter out low-engagement content (like spam), but setting them too high may result in no images showing up. Adjust these based on the activity level of the instance and hashtag you're targeting.
URL Parameters: For power users, you can also configure via query string.
Honestly, the configuration page is your best bet for finding out what works where without digging into the code. Each platform has different capabilities and limitations when it comes to filtering. But have at it!
?adapter=mastodon&instance=mastodon.social&tag=photography&minFavouritesCount=10
| Parameter | Example | Description |
|---|---|---|
adapter |
mastodon |
Platform: mastodon, bluesky, piefed, lemmy, vernissage, holos |
instance |
mastodon.social |
Instance domain (each adapter has a default) |
tag |
photography |
Hashtag to search (without #) |
actor |
user@instance |
User or community to filter by |
feed |
photography@piefed.social |
Feed ID (BlueSky, PieFed) |
pageLimit |
20 |
Results per page |
maxImages |
50 |
Stop loading after this many images |
maxPages |
5 |
Stop loading after this many pages |
excludeReposts |
true |
Hide boosts/reposts |
excludeBots |
true |
Hide bot accounts |
excludeSensitive |
true |
Hide NSFW/sensitive content (default: true) |
excludeAiGenerated |
true |
Hide AI-generated images (default: true) |
minFavouritesCount |
3 |
Minimum likes to show |
minRepostsCount |
1 |
Minimum boosts to show |
Supported Platforms
| Platform | Filters Supported |
|---|---|
| BlueSky | Actor, Feed, Tag |
| Holos | Tag |
| Lemmy | Actor, Tag |
| Mastodon | Actor, Tag |
| PieFed | Actor, Feed, Tag |
| Vernissage | Tag |
Deploy It
This is a static site - no build step, no dependencies to install. Just put the public/ folder somewhere that serves HTML.
Netlify Drop
The fastest way to get this live. No account required to start.
- Download or clone this repo
- Go to Netlify Drop
- Drag the
public/folder onto the page - You've got a live URL
Netlify will give you a random subdomain. Create a free account to keep it and optionally add a custom domain.
Neocities
Neocities is a spiritual successor to GeoCities and a great home for indie web projects. I have a tender place in my heart for Neocities and the like, because GeoCities is where I got my start with HTML coding.
- Create a free account at neocities.org
- Go to your dashboard and create a new site, then upload the contents of the
public/folder through the web interface to get started - Or go geeky and install the CLI:
gem install neocities(or usenpm install -g neocitiesif you prefer) - Deploy:
cd public
neocities push .
Any Static Host
Since there's no build step, this works anywhere that serves static files - Surge (npx surge public/), any web server, even a USB stick opened in a browser. The public/ folder is the entire site.
I just found Surge and it's fantastically free for quick static hosting. You can deploy in seconds with npx surge public/ and get a random subdomain or use your own. You can setup a single custom domain (and sub-domains) free as well.
Platform Adapters
Each platform adapter lives in its own file under public/scripts/adapters/ and encapsulates platform-specific logic:
- API URL building and pagination specific to the platform
- Data extraction from different JSON structures
- Privacy handling for platform-specific opt-out mechanisms
Respecting Privacy and Privacy Intent Conventions
Wherever possible, the gallery respects the privacy settings and conventions of the platforms it connects to. This includes:
- Account flags (
discoverable,indexable) - Bio opt-out terms (
#noindex,#nobot,#noai,#nobridge) - Platform-specific labels and NSFW flags
Content Filtering
- Minimum engagement thresholds (likes, reposts)
- NSFW/sensitive content filtering
- Bot account filtering
- Repost/boost filtering
- Image deduplication via blurhash + dimensions
Rate Limit Handling
Fediverse instances protect their resources by limiting how many images can be loaded in a short time. This gallery respects those limits:
- Conservative defaults - Loads up to 50 images across 5 pages by default
- Configurable limits - Use
maxImagesandmaxPagesURL parameters to adjust - Fallback for failed images - If images fail to load (e.g., due to rate limiting or the original source no longer exists), the card shows "View Remotely" and links to the original post
- Auto-stop - If too many images fail consecutively, loading API requests end to avoid hammering the instance
These limits exist because we're guests on federated instances. Some smaller instances have stricter limits than larger ones like mastodon.social.
Remember, the gallery is designed to be a fun way to explore content on the open web, not a tool for mass downloading or scraping. Always respect the resources and rules of the instances you're connecting to! Be cool.
Accessibility
Every project I build, I attempt to learn more about accessibility and adhere as much as I can. I know I have things wrong, so please let me know if you have suggestions for improvement!
Resources
License
MIT License. See LICENSE for details.
Dependencies
This project uses external libraries (all loaded from CDN or local copies):
- Lucide Icons - Icon library for UI elements
- Fast Blurhash - Image placeholder algorithm (local copy)
- PicoCSS - Minimal CSS framework (configuration page only)
Fast Blurhash, version 1.1.4, is included as a local script for better performance and reliability, while Lucide Icons is loaded from a CDN for ease of use.
Support
If you enjoy this project or find it useful, you can buy me a coffee on Ko-fi. Not expected, but always appreciated!