Userscripts that ship alternative experiences for legacy web applications — redesigns, not tweaks.
One .user.js file per install unit at the repo root. There is no build
step: a userscript manager copies the file verbatim, so whatever is committed
here is exactly what runs in the browser. That is a deliberate constraint, not a
missing feature — it means the published artefact and the reviewable source are
the same bytes.
Host is where the script is published: Greasy Fork for general sites, Sleazy Fork for scripts targeting adult sites. Greasy Fork will reject or relocate the latter — see CONTRIBUTING.md.
- Install a userscript manager. These are developed against Violentmonkey; Tampermonkey and Greasemonkey are expected to work but are not tested.
- Install from the listing linked in the catalogue (the green Install
button on Greasy Fork / Sleazy Fork). That copy carries the fork's own
@updateURL, so your manager picks up every new version automatically.
The files in this repository are the source, not the install channel.
There is no @updateURL or @downloadURL in any script here, by design:
pointed at a repository, those let a push to main mutate an installed copy on
every user's machine with no review. Installing a raw file from here works, but
it will never update itself — re-install by hand, or switch to the listing.
These are not style preferences. Each one is here because its absence broke something real.
- Anchor on ARIA roles,
hrefvalues and data attributes — never a generated class name. Framework class names are compiler output and rotate without notice.aria-labelis not an anchor either: it is localised, so a selector built on one matches nothing on a non-English UI. !importantis not the top of the cascade — a running animation is. A Web Animation ontransformoutranks author-important. Move things off-canvas with thetranslatelonghand (composes) rather thantransform(competes).:has()matches ancestors. Pair a content test with a structural one and confirm the match count is exactly what you intend before you hide anything.- Assert state from the DOM each pass, never latch it in a variable.
- Teardown contract. Register a teardown on
windowand call any previous one at entry. Never early-return on an "already initialised" flag — that makes a re-run a silent no-op and hides double-injection bugs. - Observer discipline.
childList-only onhead/documentElement; neversubtreeon a large or virtualised DOM. - Failure mode is always degrade to stock. When a selector is renamed upstream, rules stop matching and the page renders as the site intended. A script that mangles the page on a miss is a defect, not a degradation.
Per-script reasoning — the measured, dated evidence for why each selector and cascade trick is what it is — lives in that script's own header comments.
New scripts and fixes are welcome. Start with CONTRIBUTING.md
— it covers the metadata block rules, the two lint gates, and the @version
trap that has bitten this project more than once.
- 🐛 Report a bug
- ✨ Request a script
- 🔒 Report a security issue — not via a public issue
- 📜 Code of Conduct
MIT — see LICENSE. Contributions are accepted under the same terms.