Altifier #
Scan your Bluesky posts for missing alt text and fix them with AI-generated descriptions.
Features #
- Scan your posts: Enumerate all your Bluesky posts and replies, finding images that lack alt text
- AI-powered alt text: Generates descriptive alt text using vision AI, following Section 508 guidelines
- Review and edit: Preview generated alt text, edit inline, and approve before applying
- Bluesky OAuth login: Authenticate securely with your Bluesky/ATProto account
What this does #
Altifier scans the image posts (app.bsky.feed.post records with app.bsky.embed.images) in your PDS, identifies images missing alt text, generates descriptions via AI, and lets you apply them by recreating your posts with alt text included.
Note: Recreating a post with alt text deletes the original and creates a new one. Likes, reposts, quotes, and replies on the original post are lost.
Development #
npm install
npm start
Build #
npm run build
The build/ directory contains the static site ready for deployment.
Deployment #
This app is a fully static React SPA and can be deployed to:
- Wisp.place:
wispctl deploy <handle> --path ./build --site altifier --spa - Tangled: Configure the repo's Sites settings with deploy directory
/build - Any static host: Serve the
build/directory with SPA fallback toindex.html
AI Setup #
Altifier uses Google Gemini (BYO-key) for alt text generation. The exact
model lives in one place: src/utils/altGenerator.js (GEMINI_MODEL).
The key is never bundled or baked into the build. Each user pastes
their own key once in the app's AI Settings; it is stored only in
localStorage key altifier.geminiKey and sent directly to Google's API
in the x-goog-api-key header. If no key is set, Generate buttons are
hidden and manual alt-text entry still works.
Get a free API key at aistudio.google.com.
OAuth Configuration #
OAuth client metadata lives in public/client-metadata.json — the single
source of truth (served at /client-metadata.json). AuthContext fetches
it at startup, so there is no second copy to drift. If you change the
client_id / redirect_uris / scope in that file, the OAuth flow breaks with
opaque failures.
License #
MIT
- JavaScript 91%
- TypeScript 8%
- CSS <1%
- Shell <1%
- HTML <1%