A userscript that improves GitHub with a full settings panel and an image gallery for rendered markdown — read every picture of a README, wiki page, issue or comment in one fullscreen viewer instead of opening files one by one.
Status: early (
0.3.2). Settings panel (General · Gallery · Backup · About) and the markdown image gallery. More GitHub improvements planned.
The script's
@updateURL/@downloadURLpoint at GitHubmain— the raw install URL below is always the newest build.
Install URL (GitHub — newest):
https://raw.githubusercontent.com/NemoKing1210/github-plus/main/github-plus.user.js
| Manager | Path |
|---|---|
| Tampermonkey | Dashboard → Utilities → Install from URL |
| Violentmonkey | Dashboard → + → Install from URL |
| Greasemonkey | Add-on menu → New User Script → paste the raw URL |
| ScriptCat | Install the extension, then Install from URL with the GitHub raw URL |
github-plus.user.js in this repository (or run npm run build after cloning).The script includes @updateURL and @downloadURL metadata pointing to the
raw GitHub file, so supported managers update it automatically.
Release steps for maintainers: see docs/DEVELOPMENT.md § Releasing.
Every rendered markdown container on GitHub is one gallery set:
.md file, a
wiki page, an issue, a pull request, a review comment (anywhere GitHub
renders .markdown-body) — and it opens fullscreen in the built-in viewer.←/→ (or the arrows) walk the other images of
the same container, a centered thumbnail strip jumps anywhere, and the
counter shows where you are.+/−, double click and pinch zoom up to the
configured ceiling; drag to move the image at any zoom; 0 resets; r
rotates; the neighbouring images are preloaded so browsing feels instant./blob/ page, an uploaded attachment, any image URL), that
file is probed and swapped in, so you get the original resolution without a
broken image if it is unavailable.Open it from the gear button in the GitHub header, from the GitHub Plus
settings row in your avatar menu (right under GitHub's own Settings), or
from the userscript manager's menu command. Changes are draft-based: nothing is
stored until you press Save; Cancel, the overlay click and Escape
discard the draft; Reset to defaults asks for confirmation first.
Stored under gp_settings_v1.
| Key | Default | Notes |
|---|---|---|
language |
'auto' |
Settings-panel UI language ('auto' follows the browser) |
gallery.enabled |
true |
Master switch for the markdown image gallery |
gallery.sources.markdown |
true |
Per-source switch (one entry per registered source) |
gallery.skipBadges |
true |
Skip badge services (including badges behind GitHub's camo proxy and Actions status badges), emoji, images ≤ 40 px tall and images smaller than 80 px on both axes |
gallery.upgradeFullSize |
true |
Probe and load the linked full-size original |
gallery.thumbnails |
true |
Thumbnail strip in the viewer |
gallery.loop |
true |
Wrap around from the last image to the first |
gallery.maxZoom |
8 |
Zoom ceiling (2× … 16×) |
toasts.enabled |
true |
Toast notifications |
toasts.position |
'bottom-right' |
bottom-right, bottom-left, top-right, top-left |
toasts.duration |
5000 |
Auto-hide delay in ms (0 keeps a toast until dismissed) |
The gallery is a small framework plus one source per place images live, so adding a new place never touches the gallery itself:
| File | Role |
|---|---|
src/ui/viewer.js |
The lightbox: openViewer({ images, index, loop, thumbnails, minZoom, maxZoom, resolveImage, labels, onClose }), plus closeViewer() / isViewerOpen(). Self-contained — it can be reused by any feature. |
src/gallery/sources.js |
Source registry: registerSource, listSources. |
src/gallery/collect.js |
Collection: normalization, filtering (badges/emoji/small icons), de-duplication, cap. |
src/gallery/index.js |
Wiring: one capture-phase click listener, the generated cursor affordance stylesheet, settings listener. |
src/gallery/sources/markdown.js |
The markdown source: containers, image lookup, full-size resolution. |
Because the affordance is CSS built from the registry and the click handling is a single delegated listener that walks the live DOM, the gallery keeps working across GitHub's client-side navigation and React re-renders without a scan loop or per-image bookkeeping.
import { registerSource } from '../sources.js';
registerSource({
id: 'mySurface', // also the settings switch key (gallery.sources.mySurface)
labelKey: 'source.mySurface',
hintKey: 'source.mySurfaceDesc',
containerSelector: '.my-surface', // one container = one gallery set
cursorSelector: '.my-surface img', // gets cursor: zoom-in while enabled
collect(container) {
// return [{ node, src, alt?, title?, href? }]
},
resolveFull(item) {
// return the best full-size URL for item, or '' when unknown
},
});
Then add the switches in four places together: the source module + its import,
DEFAULT_GALLERY.sources.<id> in src/core/constants.js, and the
source.<id> / source.<id>Desc keys in all ten
src/i18n/locales/*.js files. The settings panel picks the new source up from
the registry automatically.
Requires Node.js 22 (see .nvmrc).
npm install
npm run dev # vite-plugin-monkey dev server (dev: prefix)
npm run build # vite build + copy dist/ → root artifacts
npm run verify:artifacts # fail if dist/