{"id":13500622,"url":"https://github.com/cheeaun/phanpy","last_synced_at":"2026-01-07T14:17:09.021Z","repository":{"id":64851665,"uuid":"575800196","full_name":"cheeaun/phanpy","owner":"cheeaun","description":"A minimalistic opinionated Mastodon web client","archived":false,"fork":false,"pushed_at":"2025-05-06T22:59:41.000Z","size":49954,"stargazers_count":1244,"open_issues_count":392,"forks_count":131,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-05-06T23:30:43.344Z","etag":null,"topics":["mastodon","mastodon-client","pwa","web"],"latest_commit_sha":null,"homepage":"https://phanpy.social","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cheeaun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"cheeaun","buy_me_a_coffee":"cheeaun","patreon":"cheeaun","custom":["https://revolut.me/cheeaun","https://donate.stripe.com/9AQeVfbr40ZB9nGaEF","https://paypal.me/cheeaun"]}},"created_at":"2022-12-08T10:24:31.000Z","updated_at":"2025-05-06T22:56:41.000Z","dependencies_parsed_at":"2023-02-10T15:16:07.379Z","dependency_job_id":"5e2f8d4f-0f84-46be-8d72-d6ff5f2dae5f","html_url":"https://github.com/cheeaun/phanpy","commit_stats":{"total_commits":3218,"total_committers":24,"mean_commits":"134.08333333333334","dds":"0.027035425730267293","last_synced_commit":"af6cf2715c124d26a1420361e3df043538483be5"},"previous_names":[],"tags_count":71,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheeaun%2Fphanpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheeaun%2Fphanpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheeaun%2Fphanpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cheeaun%2Fphanpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cheeaun","download_url":"https://codeload.github.com/cheeaun/phanpy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254170050,"owners_count":22026219,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["mastodon","mastodon-client","pwa","web"],"created_at":"2024-07-31T22:01:07.280Z","updated_at":"2026-01-07T14:17:09.014Z","avatar_url":"https://github.com/cheeaun.png","language":"JavaScript","funding_links":["https://github.com/sponsors/cheeaun","https://buymeacoffee.com/cheeaun","https://patreon.com/cheeaun","https://revolut.me/cheeaun","https://donate.stripe.com/9AQeVfbr40ZB9nGaEF","https://paypal.me/cheeaun"],"categories":["JavaScript","Alternative Web Front-ends","Desktop Clients"],"sub_categories":["Mastodon"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"design/logo-4.svg\" width=\"128\" height=\"128\" alt=\"\"\u003e\n\nPhanpy\n===\n\n**Minimalistic opinionated Mastodon web client.**\n\u003c/div\u003e\n\n![Fancy screenshot](readme-assets/fancy-screenshot.jpg)\n\n**🗣️ Pronunciation**: `/fænpi/` ([`FAN-pee`](https://www.smogon.com/forums/threads/the-official-name-pronunciation-guide.3474941/)) [🔊 Listen](https://www.youtube.com/watch?v=DIUbWe-ysJI)\n\nThis is an alternative web client for [Mastodon](https://joinmastodon.org/).\n\n- 🏢 **Production**: https://phanpy.social [![Uptime Robot status](https://img.shields.io/uptimerobot/status/m795572454-df4518f96a3784401b550a6c)](https://stats.uptimerobot.com/rVO1RkbwMB)\n  - ![GitHub Release](https://img.shields.io/github/v/release/cheeaun/phanpy)\n  - `production` branch\n  - break less often\n  - slower fixes unless critical\n- 🏗️ **Development**: https://dev.phanpy.social [![Uptime Robot status](https://img.shields.io/uptimerobot/status/m801824077-77302887dc81a5ac4a45e231)](https://stats.uptimerobot.com/rVO1RkbwMB)\n  - ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/cheeaun/phanpy/main)\n  - `main` branch\n  - may see new cool stuff sooner\n  - may break more often\n  - may be fixed much faster too\n\n🐘 Follow [@phanpy on Mastodon](https://hachyderm.io/@phanpy) for updates ✨\n\nEverything is designed and engineered following my taste and vision. This is a personal side project for me to learn about Mastodon and experiment with new UI/UX ideas.\n\n## Features\n\n- 👪 Multiple accounts\n- 🪟 Compose window pop-out/in\n- 🌗 Light/dark/auto theme\n- 🔔 Grouped notifications\n- 🪺 Nested comments thread\n- 📬 Unsent draft recovery\n- 🎠 Boosts Carousel™️\n- ⚡ Shortcuts™️ with view modes like multi-column or tab bar\n- #️⃣ Multi-hashtag timeline\n\n## Design decisions\n\n- **Status actions (reply, boost, favourite, bookmark, etc) are hidden by default**.\u003cbr\u003eThey only appear in individual status page. This is to reduce clutter and distraction. It may result in lower engagement, but we're not chasing numbers here.\n- **Boost is represented with the rocket icon**.\u003cbr\u003eThe green double arrow icon (retweet for Twitter) doesn't look right for the term \"boost\". Green rocket looks weird, so I use purple.\n- **Short usernames (`@username`) are displayed in timelines, instead of the full account username (`@username@instance`)**.\u003cbr\u003eDespite the [guideline](https://docs.joinmastodon.org/api/guidelines/#username) mentioned that \"Decentralization must be transparent to the user\", I don't think we should shove it to the face every single time. There are also some [screen-reader-related accessibility concerns](https://twitter.com/lifeofablindgrl/status/1595864647554502656) with the full username, though this web app is unfortunately not accessible yet.\n- **No autoplay for video/GIF/whatever in timeline**.\u003cbr\u003eThe timeline is already a huge mess with lots of people, brands, news and media trying to grab your attention. Let's not make it worse. (Current exception now would be animated emojis.)\n- **Hash-based URLs**.\u003cbr\u003eThis web app is not meant to be a full-fledged replacement to Mastodon's existing front-end. There's no SEO, database, serverless or any long-running servers. I could be wrong one day.\n\n## Subtle UI implementations\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003cb\u003eUser name display\u003c/b\u003e\n\u003c/summary\u003e\n\n![User name display](readme-assets/user-name-display.jpg)\n\n- On the timeline, the user name is displayed as `[NAME] @[username]`.\n- For the `@[username]`, always exclude the instance domain name.\n- If the `[NAME]` *looks the same* as the `@[username]`, then the `@[username]` is excluded as well.\n\u003c/details\u003e\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003cb\u003eBoosts Carousel\u003c/b\u003e\n\u003c/summary\u003e\n\n![Boosts Carousel](readme-assets/boosts-carousel.jpg)\n\n- From the fetched posts (e.g. 20 posts per fetch), if number of boosts are more than quarter of total posts or more than 3 consecutive boosts, boosts carousel UI will be triggered.\n- If number of boosts are more than 3 quarters of total posts, boosts carousel UI will be slotted at the end of total posts fetched (per \"page\").\n- Else, boosts carousel UI will be slotted in between the posts.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003cb\u003eThread number badge (e.g. Thread 1/X)\u003c/b\u003e\n\u003c/summary\u003e\n\n![Thread number badge](readme-assets/thread-number-badge.jpg)\n\n- Check every post for `inReplyToId` from cache or additional API requests, until the root post is found.\n- If root post is found, badge will show the index number of the post in the thread.\n- Limit up to 3 API requests as the root post may be very old or the thread is super long.\n- If index number couldn't be found, badge will fallback to showing `Thread` without the number.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003cb\u003eHashtag stuffing collapsing\u003c/b\u003e\n\u003c/summary\u003e\n\n![Hashtag stuffing collapsing](readme-assets/hashtag-stuffing-collapsing.jpg)\n\n- First paragraph of post content with more than 3 hashtags will be collapsed to max 3 lines.\n- Subsequent paragraphs after first paragraph with more than 3 hashtags will be collapsed to 1 line.\n- Adjacent paragraphs with more than 1 hashtag after collapsed paragraphs will be collapsed to 1 line.\n- If there are text around or between the hashtags, they will not be collapsed.\n- Collapsed hashtags will be appended with `...` at the end.\n- They are also slightly faded out to reduce visual noise.\n- Opening the post view will reveal the hashtags uncollapsed.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003cb\u003eFiltered posts\u003c/b\u003e\n\u003c/summary\u003e\n\n- \"Hide completely\"-filtered posts will be hidden, with no UI to reveal it.\n- \"Hide with a warning\"-filtered posts will be partially hidden, showing the filter name and author name.\n  - Content can be partially revealed by hovering over the post, with tooltip showing the post text.\n  - Clicking it will open the Post page.\n  - Long-pressing or right-clicking it will \"peek\" the post with a bottom sheet UI.\n  - On boosts carousel, they are sorted to the end of the carousel.\n\u003c/details\u003e\n\n## Development\n\nPrerequisites: Node.js 20+\n\n- `npm install` - Install dependencies\n- `npm run dev` - Start development server and `messages:extract` (`clean` + `watch`) in parallel\n- `npm run build` - Build for production\n- `npm run preview` - Preview the production build\n- `npm run fetch-instances` - Fetch instances list from [joinmastodon.org/servers](https://joinmastodon.org/servers), save it to `src/data/instances.json`\n- `npm run sourcemap` - Run `source-map-explorer` on the production build\n- `npm run messages:extract` - Extract messages from source files and update the locale message catalogs\n- `npm run git:po-filter` - Configure `git` to use `po-filter` for diffing `.po` files\n\n## Tech stack\n\n- [Vite](https://vitejs.dev/) - Build tool\n- [Preact](https://preactjs.com/) - UI library\n- [Valtio](https://valtio.pmnd.rs/) - State management\n- [React Router](https://reactrouter.com/) - Routing\n- [masto.js](https://github.com/neet/masto.js/) - Mastodon API client\n- [Iconify](https://iconify.design/) - Icon library\n  - [MingCute icons](https://www.mingcute.com/)\n- [Lingui](https://lingui.dev/) - Internationalization\n- Vanilla CSS - _Yes, I'm old school._\n\nSome of these may change in the future. The front-end world is ever-changing.\n\n## Internationalization\n\nAll translations are available as [gettext](https://en.wikipedia.org/wiki/Gettext) `.po` files in the `src/locales` folder. The default language is English (`en`). [CLDR Plural Rules](https://cldr.unicode.org/index/cldr-spec/plural-rules) are used for pluralization. RTL (right-to-left) languages are also supported with proper text direction, icon rendering and layout.\n\nOn page load, default language is detected via these methods, in order (first match is used):\n\n1. URL parameter `lang` e.g. `/?lang=zh-Hant`\n2. `localStorage` key `lang`\n3. Browser's `navigator.language`\n\nUsers can change the language in the settings, which sets the `localStorage` key `lang`.\n\n### Guide for translators\n\n*Inspired by [Translate WordPress Handbook](https://make.wordpress.org/polyglots/handbook/):\n\n- [Don’t translate literally, translate organically](https://make.wordpress.org/polyglots/handbook/translating/expectations/#dont-translate-literally-translate-organically).\n- [Try to keep the same level of formality (or informality)](https://make.wordpress.org/polyglots/handbook/translating/expectations/#try-to-keep-the-same-level-of-formality-or-informality)\n- [Don’t use slang or audience-specific terms](https://make.wordpress.org/polyglots/handbook/translating/expectations/#try-to-keep-the-same-level-of-formality-or-informality)\n- Be attentive to placeholders for variables. Many strings have placesholders e.g. `{account}` (variable), `\u003c0\u003e{name}\u003c/0\u003e` (tag with variable) and `#` (number placeholder).\n- [Ellipsis](https://en.wikipedia.org/wiki/Ellipsis) (…) is intentional. Don't remove it.\n  - Nielsen Norman Group: [\"Include Ellipses in Command Text to Indicate When More Information Is Required\"](https://www.nngroup.com/articles/ui-copy/)\n  - Apple Human Interface Guidelines: [\"Append an ellipsis to a menu item’s label when the action requires more information before it can complete. The ellipsis character (…) signals that people need to input information or make additional choices, typically within another view.\"](https://developer.apple.com/design/human-interface-guidelines/menus)\n  - Windows App Development: [\"Ellipses mean incompleteness.\"](https://learn.microsoft.com/en-us/windows/win32/uxguide/text-ui)\n- Date timestamps, date ranges, numbers, language names and text segmentation are handled by the [ECMAScript Internationalization API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl).\n  - [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) - e.g. \"8 Aug\", \"08/08/2024\"\n  - [`Intl.RelativeTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat) - e.g. \"2 days ago\", \"in 2 days\"\n  - [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat) - e.g. \"1,000\", \"10K\"\n  - [`Intl.DisplayNames`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) - e.g. \"English\" (`en`) in Traditional Chinese (`zh-Hant`) is \"英文\"\n  - [`Intl.Locale`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale) (with polyfill for older browsers)\n  - [`Intl.Segmenter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter) (with polyfill for older browsers)\n\n### Technical notes\n\n- IDs for strings are auto-generated instead of explicitly defined. Some of the [benefits](https://lingui.dev/tutorials/explicit-vs-generated-ids#benefits-of-generated-ids) are avoiding the \"naming things\" problem and avoiding duplicates.\n  - Explicit IDs might be introduced in the future when requirements and priorities change. The library (Lingui) allows both.\n  - Please report issues if certain strings are translated differently based on context, culture or region.\n- There are no strings for push notifications. The language is set on the instance server.\n- Native HTML date pickers, e.g. `\u003cinput type=\"month\"\u003e` will always follow the system's locale and not the user's set locale.\n- \"ALT\" in ALT badge is not translated. It serves as a a recognizable standard across languages.\n- Custom emoji names are not localized, therefore searches don't work for non-English languages.\n- GIPHY API supports [a list of languages for searches](https://developers.giphy.com/docs/optional-settings/#language-support).\n- Unicode Right-to-left mark (RLM) (`U+200F`, `\u0026rlm;`) may need to be used for mixed RTL/LTR text, especially for [`\u003ctitle\u003e` element](https://www.w3.org/International/questions/qa-html-dir.en.html#title_element) (`document.title`).\n- On development, there's an additional `pseudo-LOCALE` locale, used for [pseudolocalization](https://en.wikipedia.org/wiki/Pseudolocalization). It's for testing and won't show up on production.\n- When building for production, English (`en`) catalog messages are not bundled separatedly. Other locales are bundled as separate files and loaded on demand. This ensures that `en` is always available as fallback.\n\n### Volunteer translations\n\n[![Crowdin](https://badges.crowdin.net/phanpy/localized.svg)](https://crowdin.com/project/phanpy)\n\n[![Languages chart](https://badges.awesome-crowdin.com/translation-14836566-703337.png)](https://crowdin.com/project/phanpy)\n\nTranslations are managed on [Crowdin](https://crowdin.com/project/phanpy). You can help by volunteering translations.\n\nRead the [intro documentation](https://support.crowdin.com/for-volunteer-translators/) to get started.\n\n## Self-hosting\n\nThis is a **pure static web app**. You can host it anywhere you want.\n\nTwo ways (choose one):\n\n### Easy way\n\nGo to [Releases](https://github.com/cheeaun/phanpy/releases) and download the latest `phanpy-dist.zip` or `phanpy-dist.tar.gz`. It's pre-built so don't need to run any install/build commands. Extract it. Serve the folder of extracted files.\n\n\u003e [!IMPORTANT]\n\u003e Text translations connect to an **external service** (`translang.phanpy.social`).\n\n### Custom-build way\n\nRequires [Node.js](https://nodejs.org/).\n\nDownload or `git clone` this repository. Use `production` branch for *stable* releases, `main` for *latest*. Build it by running `npm run build` (after `npm install`). Serve the `dist` folder.\n\n\u003e [!IMPORTANT]\n\u003e Text translations connect to an **external service** (`translang.phanpy.social`). This can be configured with environment variables if you want to [self-host your own instance](#translang-api-hosting).\n\nCustomization can be done by passing environment variables to the build command. Examples:\n\n```bash\nPHANPY_CLIENT_NAME=\"Phanpy Dev\" \\\n    PHANPY_WEBSITE=\"https://dev.phanpy.social\" \\\n    npm run build\n```\n\n```bash\nPHANPY_DEFAULT_INSTANCE=hachyderm.io \\\n    PHANPY_DEFAULT_INSTANCE_REGISTRATION_URL=https://hachyderm.io/auth/sign_up \\\n    PHANPY_PRIVACY_POLICY_URL=https://hachyderm.io/privacy-policy \\\n    npm run build\n```\n\nIt's also possible to set them in the `.env` file.\n\nAvailable variables:\n\n- `PHANPY_CLIENT_NAME` (optional, default: `Phanpy`) affects:\n  - Web page title, shown in the browser window or tab title\n  - App title, when installed as PWA, shown in the Home screen, macOS dock, Windows taskbar, etc\n  - OpenGraph card title, when shared on social networks\n  - Client name, when [registering the app for authentication](https://docs.joinmastodon.org/client/token/#app) and shown as client used on posts in some apps/clients\n- `PHANPY_WEBSITE` (optional but recommended, no defaults) affects:\n  - Canonical URL of the website\n  - OpenGraph card URL, when shared on social networks\n  - Root path for the OpenGraph card image\n  - Client URL, when [registering the app for authentication](https://docs.joinmastodon.org/client/token/#app) and shown as client used on posts in some apps/clients\n- `PHANPY_DEFAULT_INSTANCE` (optional, no defaults):\n  - e.g. 'mastodon.social', without `https://`\n  - Default instance for log-in\n  - When logging in, the user will be redirected instantly to the instance's authentication page instead of having to manually type the instance URL and submit\n- `PHANPY_DEFAULT_INSTANCE_REGISTRATION_URL` (optional, no defaults):\n  - URL of the instance registration page\n  - E.g. `https://mastodon.social/auth/sign_up`\n- `PHANPY_PRIVACY_POLICY_URL` (optional, default to official instance's privacy policy):\n  - URL of the privacy policy page\n  - May specify the instance's own privacy policy\n- `PHANPY_DEFAULT_LANG` (optional):\n  - Default language is English (`en`) if not specified.\n  - Fallback language after multiple detection methods (`lang` query parameter, `lang` key in `localStorage` and `navigator.language`)\n- `PHANPY_REFERRER_POLICY` (optional, default: `origin`):\n  - Referrer policy for the site. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy).\n  - This is applied with the `\u003cmeta\u003e` tag on the client-side.\n  - The policy can also be set with `Referrer-Policy` header configured on the server-side (not this variable).\n  - Note that since Phanpy uses hash-based URLs, the referrer does not include the hash part.\n- `PHANPY_LINGVA_INSTANCES` (**DEPRECATED**, optional, space-separated list, default: `lingva.phanpy.social [...hard-coded list of fallback instances]`):\n  - Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.\n  - May specify a self-hosted Lingva instance, powered by either [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api)\n  - List of fallback instances hard-coded in `/.env`\n  - [↗️ List of lingva-translate instances](https://github.com/thedaviddelta/lingva-translate?tab=readme-ov-file#instances)\n- `PHANPY_TRANSLANG_INSTANCES` (optional, space-separated list, default: `translang.phanpy.social`):\n  - Specify a space-separated list of instances. First will be used as default before falling back to the subsequent instances. If there's only 1 instance, means no fallback.\n  - May specify a self-hosted Translating instance, powered by [translang-api](https://github.com/cheeaun/translang-api).\n  - List of instances hard-coded in `/.env`\n- `PHANPY_IMG_ALT_API_URL` (optional, no defaults):\n  - API endpoint for self-hosted instance of [img-alt-api](https://github.com/cheeaun/img-alt-api).\n  - If provided, a setting will appear for users to enable the image description generator in the composer. Disabled by default.\n- `PHANPY_GIPHY_API_KEY` (optional, no defaults):\n  - API key for [GIPHY](https://developers.giphy.com/). See [API docs](https://developers.giphy.com/docs/api/).\n  - If provided, a setting will appear for users to enable the GIF picker in the composer. Disabled by default.\n  - This is not self-hosted.\n- `PHANPY_DISALLOW_ROBOTS` (optional, default: not set):\n  - Set to any value (`true`, `1`, etc) to override the robots.txt file and disallow all web crawlers from indexing the site\n\n### Static site hosting\n\nTry online search for \"how to self-host static sites\" as there are many ways to do it.\n\n#### Lingva-translate or lingva-api hosting\n\n⚠️ **DEPRECATED**. See documentation for [lingva-translate](https://github.com/thedaviddelta/lingva-translate) or [lingva-api](https://github.com/cheeaun/lingva-api).\n\n#### Translang API hosting\n\nSee documentation for [translang-api](https://github.com/cheeaun/translang-api).\n\n### Keeping up with releases\n\n1. 👀 Watch this repo for releases.\n2. 🛜 Subscribe to the feed: https://github.com/cheeaun/phanpy/releases.atom\n3. 👉 Follow [Phanpy](https://hachyderm.io/@phanpy) on Mastodon.\n4. ➡️ Query JSON:\n   - Production: https://phanpy.social/version.json\n   - Development: https://dev.phanpy.social/version.json\n\nChangelog available here: [CHANGELOG.md](CHANGELOG.md)\n\n## Community deployments\n\nThese are self-hosted by other wonderful folks.\n\n- [ferengi.one](https://m.ferengi.one/) by [@david@weaknotes.com](https://weaknotes.com/@david)\n- [halo.mookiesplace.com](https://halo.mookiesplace.com) by [@mookie@suigow.xyz](https://suigow.xyz/@mookie)\n- [phanpy.app](https://phanpy.app) by [@bumble@ibe.social](https://ibe.social/@bumble)\n- [phanpy.bauxite.tech](https://phanpy.bauxite.tech) by [@b4ux1t3@hachyderm.io](https://hachyderm.io/@b4ux1t3)\n- [phanpy.blaede.family](https://phanpy.blaede.family/) by [@cassidy@blaede.family](https://mastodon.blaede.family/@cassidy)\n- [phanpy.crmbl.uk](https://phanpy.crmbl.uk) by [@snail@crmbl.uk](https://mstdn.crmbl.uk/@snail)\n- [phanpy.cz](https://phanpy.cz) by [@zdendys@mamutovo.cz](https://mamutovo.cz/@zdendys)\n- [phanpy.fulda.social](https://phanpy.fulda.social) by [@Ganneff@fulda.social](https://fulda.social/@Ganneff)\n- [phanpy.gotosocial.social](https://phanpy.gotosocial.social/) by [@admin@gotosocial.social](https://gotosocial.social/@admin)\n- [phanpy.hear-me.social](https://phanpy.hear-me.social) by [@admin@hear-me.social](https://hear-me.social/@admin)\n- [phanpy.mastodon.world](https://phanpy.mastodon.world) by [@ruud@mastodon.world](https://mastodon.world/@ruud)\n- [phanpy.mstdn.mx](https://phanpy.mstdn.mx/) by [@maop@mstdn.mx](https://mstdn.mx/@maop)\n- [phanpy.social.tchncs.de](https://phanpy.social.tchncs.de) by [@milan@social.tchncs.de](https://social.tchncs.de/@milan)\n- [phanpy.tilde.zone](https://phanpy.tilde.zone) by [@ben@tilde.zone](https://tilde.zone/@ben)\n- [phanpy.vmst.io](https://phanpy.vmst.io/) by [@vmstan@vmst.io](https://vmst.io/@vmstan)\n- [phanpy.linuxusers.in](https://phanpy.linuxusers.in) by [@dharmik@linuxusers.in](https://linuxusers.in/dharmik)\n- [phanpy.blablalinux.be](https://phanpy.blablalinux.be) by [@blablalinux@mastodon.blablalinux.be](https://mastodon.blablalinux.be/@blablalinux)\n- [fedi.woodpeckersnest.space](https://fedi.woodpeckersnest.space) by [@roughnecks@social.woodpeckersnest.space](https://social.woodpeckersnest.space/@roughnecks)\n\n\u003e Note: Add yours by creating a pull request.\n\n## Costs\n\nCosts involved in running and developing this web app:\n\n- Domain name (.social): **USD$23.18/year** (USD$6.87 1st year)\n- Hosting: Free\n- Development, design, maintenance: \"Free\" (My precious time)\n\n## Mascot\n\n[Phanpy](https://bulbapedia.bulbagarden.net/wiki/Phanpy_(Pok%C3%A9mon)) is a Ground-type Pokémon.\n\n## Maintainers + contributors\n\n- [Chee Aun](https://github.com/cheeaun) ([Mastodon](https://mastodon.social/@cheeaun)) ([Twitter](https://twitter.com/cheeaun))\n\n[![Contributors](https://contrib.rocks/image?repo=cheeaun/phanpy)](https://github.com/cheeaun/phanpy/graphs/contributors)\n\n### Translation volunteers\n\n\u003c!-- i18n volunteers start --\u003e\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16945821/medium/3da66a1dde4951ad34c33ca23241b864_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e A.Mason (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12571163/medium/9f3ea938f4243f5ffe2a43f814ddc9e8_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e alidsds11 (Arabic)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16180744/medium/5b04ae975b23895635130d7a176515cb_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e alternative (Korean)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16848873/medium/d8773fdb621f4c9c1b08d2c641fa519a.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e AmaseCocoa (Japanese)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13170041/medium/603136896af17fc005fd592ce3f48717_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e BoFFire (Arabic, French, Kabyle)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12898464/medium/d3758a76b894bade4bf271c9b32ea69b.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Brawaru (Russian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15460040/medium/1cfcfe5f5511b783b5d9f2b968bad819.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e cbasje (Dutch)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15525631/medium/51293156034d0236f1a1020c10f7d539_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e cbo92 (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15910131/medium/67fab7eeab5551853450e76e2ef19e59.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e CDN (Chinese Simplified)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12513809/medium/b56324e44ae26da6db7793bc467a70e2.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e codl (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16556801/medium/ed5e501ca1f3cc6525d2da28db646346.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e dannypsnl (Chinese Traditional)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/3711/medium/c97239bb54623a50eb43cc6b801bb156.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e databio (Catalan)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/17440746/medium/eb48c068ec53fbb48e870fab8bc313b0.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e detected-rage-colette (Japanese)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16533843/medium/ac7af8776858a992d992cf6702d1aaae.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e Dizro (Italian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16574625/medium/f2ac3a4f32f104a3a6d4085d4bcb3924_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Drift6944 (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12618120/medium/ccb11bd042bbf4c7189033f7af2dbd32_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e drydenwu (Chinese Traditional)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13557465/medium/8feebf3677fa80c01e8c54c4fbe097e0_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e elissarc (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16528627/medium/9036f6eced0257f4e1ea4c5bd499de2d_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e ElPamplina (Spanish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15592209/medium/28f10212dce24e74c25e27ea6d0e9126.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e filipesmedeiros (Portuguese)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14277386/medium/29b30d2c73a214000e3941c9978f49e4_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Fitik (Esperanto, Hebrew)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15791971/medium/1790a2101ceb13f61816b8fe6fbe6d90.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e fracl (Italian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14444512/medium/99d0e7a3076deccbdfe0aa0b0612308c.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e Freeesia (Japanese)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15777621/medium/9e3409aac9c20973984440aa1542b260_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e gflorian (German)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12617257/medium/7a0122f352a94d95be10780bb83f63ef.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e ghose (Galician)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15248754/medium/0dac6334ea0f4e8d4194a605c0a5594a.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e hongminhee (Korean)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16529833/medium/2122d0c5d61c00786ab6d5e5672d4098.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Hugoglyph (Esperanto, Spanish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13454728/medium/1f78b7124b3c962bc4ae55e8d701fc91_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e isard (Catalan)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16646485/medium/5d76c44212a4048a815ab437fb170856_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e kaliuwu (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16532403/medium/4cefb19623bcc44d7cdb9e25aebf5250.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e karlafej (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14677260/medium/e9f17e62ab69ed6212a16c94d779e7f3.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Kytta (German)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16529521/medium/ae6add93a901b0fefa2d9b1077920d73.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e llun (Thai)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16291756/medium/a662122faa4f9a71b259b0e561f923b4.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e lucsdev24 (Occitan, Portuguese, Portuguese, Brazilian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16640089/medium/4b7d8d275d7a7bff564adde51e09b473_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e LukeHong (Chinese Traditional)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/17345822/medium/3013b04d3a49336637e51dba33ab1a3d.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e mahefa.randimbisoa (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12822971/medium/4ecbe6d1248536084902925beb0b63e4.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Mannivu (Italian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13990351/medium/86942d51f67a5f5366c5d6385ea59b77_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e manuelviens (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16537713/medium/825f0bf1a14fc545a76891a52839d86e_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e marcin.kozinski (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16812323/medium/72bffbdf4a331845f23400eafa0b3d48.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e martinmodrak (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13044/medium/bfa55b9a0569a9e382fd694c91d3db1b_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e misk (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13521465/medium/76cb9aa6b753ce900a70478bff7fcea0.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e mkljczkk (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12882812/medium/77744d8db46e9a3e09030e1a02b7a572.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e mojosoeun (Korean)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13613969/medium/c7834ddc0ada84a79671697a944bb274.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e moreal (Korean)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14158861/medium/ba1ff31dc5743b067ea6685f735229a5_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e MrWillCom (Chinese Simplified)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15652333/medium/7f36f289f9e2fe41d89ad534a1047f0e.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e nclm (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/17450186/medium/6f5768f64963379c7ddfdccd53572c60.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e NiklasA95 (German)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15000639/medium/ebbf0bb7d5027a1903d11b7f5f34f65b.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e nycterent (Lithuanian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16539461/medium/2f41b9f0b802c1d200a6ab62167a7229_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e pazpi (Italian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15399796/medium/d7fd8457394d2c795771b72396b75099.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e poesty (Chinese Simplified)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13954917/medium/56a2cba267eb1b5d122bf62ddc0dd732_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e PPNplus (Thai)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15106977/medium/54bf93b19af8bbfdee579ea51685bafa.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e punkrockgirl (Basque)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16536247/medium/f010c8e718a36229733a8b58f6bad2a4_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e radecos (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16538917/medium/092ec03f56f9dd1cbce94379fa4d4d38.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Razem (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14345134/medium/89a299239890c79a1d791d08ec3951dc.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e realpixelcode (German)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16527325/medium/37ebb27e7a50f7f85ae93beafc7028a2.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e rezahosseinzadeh (Persian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13422319/medium/66632a98d73d48e36753d94ebcec9d4f.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e rwmpelstilzchen (Esperanto, Hebrew)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16538605/medium/bcdb6e3286b7d6237923f3a9383eed29.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e SadmL (Russian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16539171/medium/0ce95ef6b3b0566136191fbedc1563d0.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e SadmL_AI (Russian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16121928/medium/b1dd34dc3e93b64b93b94aedca0c5b7d.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e Schishka71 (Russian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/17206524/medium/1b0a8f9eafe7326be6968c6aed14c872.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e seizeheures (Esperanto)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12381015/medium/35e3557fd61d85f9a5b84545d9e3feb4.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e shuuji3 (Japanese)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14565190/medium/79100599131b7776e9803e4b696915a3_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Sky_NiniKo (French)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/17237304/medium/7954dfd36547e9d1f13266a52e9aa1b5_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e StasZin4 (Ukrainian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/13143526/medium/30871da23d51d7e41bb02f3c92d7f104.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Steffo99 (Italian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16532441/medium/1a47e8d80c95636e02d2260f6e233ca5.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Su5hicz (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/12579488/medium/699394d1acfe986a31532007534c7656.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e svetlemodry (Czech)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16530049/medium/683f3581620c6b4a5c753b416ed695a7.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e tferrermo (Spanish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15752199/medium/7e9efd828c4691368d063b19d19eb894.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e tkbremnes (Norwegian Bokmal)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16527851/medium/649e5a9a8a8cc61ced670d89e9cca082.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e tux93 (German)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16236470/medium/315b1ebbd38e0f7e41d44bee752afa33.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e Usia (Ukrainian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16791511/medium/13af704ac9b4ce8350cd2dc6b823d050.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e uzaylul (Turkish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14427566/medium/ab733b5044c21867fc5a9d1b22cd2c03.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Vac31. (Lithuanian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16026914/medium/35f400b0799c35e8e5f4556a7fa63544.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e valtlai (Finnish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16608515/medium/85506c21dce8df07843ca11908ee3951.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e vasiriri (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16355626/medium/a10a29f0016c6beb94e8219d50e8b8d7.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e voitech (Polish)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16563757/medium/af4556c13862d1fd593b51084a159b75_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e voyagercy (Chinese Traditional)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15982109/medium/9c03062bdc1d3c6d384dbfead97c26ba.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e xabi_itzultzaile (Basque)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16556017/medium/ee1fbd7646f1ac2abc18bfa96076d55a.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e xen4n (Ukrainian)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16532657/medium/f309f319266e1ff95f3070eab0c9a9d9_default.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e xqueralt (Catalan)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/15583431/medium/14973556de7721e642701bf74d6fb053.png\" alt=\"\" width=\"16\" height=\"16\" /\u003e Yukaii (Chinese Traditional)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14360216/medium/7e48473691456fce95e1be687045377c.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e Zet24 (Arabic)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/14041603/medium/6ab77a0467b06aeb49927c6d9c409f89.jpg\" alt=\"\" width=\"16\" height=\"16\" /\u003e ZiriSut (Kabyle)\n- \u003cimg src=\"https://crowdin-static.cf-downloads.crowdin.com/avatar/16530601/medium/e1b6d5c24953b6405405c1ab33c0fa46.jpeg\" alt=\"\" width=\"16\" height=\"16\" /\u003e zkreml (Czech)\n\u003c!-- i18n volunteers end --\u003e\n\n## Backstory\n\nI am one of the earliest users of Twitter. Twitter was launched on [15 July 2006](https://en.wikipedia.org/wiki/Twitter). I joined on December 2006 and my [first tweet](https://twitter.com/cheeaun/status/1298723) was posted on 18 December 2006.\n\nI know how early Twitter looks like. It was fun.\n\nBack then, I [made a Twitter clone](https://twitter.com/cheeaun/status/789031599) called \"Twig\" written in Python and Google App Engine. I almost made my own [Twitter desktop client](https://github.com/cheeaun/chidori) written in Appcelerator Titanium. I [gave one of my best talks about the Twitter client](https://www.slideshare.net/cheeaun/story-of-a-thousand-birds) in a mini-conference. I built this thing called \"Twitter [Columns](https://twitter.com/columns)\", a web app that shows your list of followings, your followings' followings, your followers, your followers' followers and so on. In 2009, I wrote a blog post titled [\"How I got started with Twitter\"](https://cheeaun.com/blog/2009/04/how-i-got-started-with-twitter/). I created [two](https://twitter.com/cheeaun/status/1273422454) [themes](https://twitter.com/cheeaun/status/1487781343) for DestroyTwitter (a desktop client made with Adobe Air by Jonnie Hallman) and one of them is called [\"Vimeo\"](https://dribbble.com/shots/31624). In 2013, I wrote [my own tweets backup site](https://github.com/cheeaun/tweets) with a front-end to view my tweets and a [CouchDB backend](https://github.com/cheeaun/tweet-couch) to store them.\n\nIt's been **more than 15 years**.\n\nAnd here I am. Building a Mastodon web client.\n\n## Alternative web clients\n\n- Phanpy forks ↓\n  - [Agora](https://agorasocial.app/)\n- [Pinafore](https://pinafore.social/) ([retired](https://nolanlawson.com/2023/01/09/retiring-pinafore/)) - forks ↓\n  - [Semaphore](https://semaphore.social/) ([archived](https://github.com/NickColley/semaphore))\n  - [Enafore](https://enafore.social/)\n- [Cuckoo+](https://www.cuckoo.social/) (down)\n- [Sengi](https://nicolasconstant.github.io/sengi/)\n- [Soapbox](https://fe.soapbox.pub/)\n- [Elk](https://elk.zone/) - forks ↓\n  - [elk.fedified.com](https://elk.fedified.com/) (gone, redirects to elk.zone)\n  - [crab](https://github.com/maybeanerd/crab)\n  - [Glowrea](https://github.com/s414june/glowrea)\n- [Mastodeck](https://mastodeck.com/)\n- [Trunks](https://trunks.social/)\n- [Tooty](https://github.com/n1k0/tooty)\n- [Litterbox](https://litterbox.koyu.space/)\n- [Statuzer](https://statuzer.com/)\n- [Tusked](https://tusked.app/) ([archived](https://github.com/raikasdev/tusked))\n- [Mastodon Glitch Edition (standalone frontend)](https://iceshrimp.dev/iceshrimp/masto-fe-standalone) - forks ↓\n  - [Masto-FE (🦥 flavour)](https://masto-fe.superseriousbusiness.org)\n- [pl-fe](https://pl.mkljczk.pl)\n- [Mangane](https://github.com/BDX-town/Mangane)\n- [TheDesk](https://github.com/cutls/TheDesk) (archived)\n- [More...](https://github.com/hueyy/awesome-mastodon/#clients)\n\n## 💁‍♂️ Notice to all other social media client developers\n\nPlease, please copy the UI ideas and experiments from this app. I think some of them are pretty good and it would be great if more apps have them.\n\nIf you're not a developer, please tell your favourite social media client developers about this app and ask them to copy the UI ideas and experiments.\n\n## License\n\n[MIT](https://cheeaun.mit-license.org/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheeaun%2Fphanpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcheeaun%2Fphanpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcheeaun%2Fphanpy/lists"}