A browser extension for devforum.roblox.com — Luau-aware code intelligence, faster navigation, and a full restyle. Chrome, Brave, Edge and Firefox 128+.
Every feature below can be turned off individually, and the redesign can be switched off while keeping the features.
Luau code intelligence. The forum highlights Luau using highlight.js's Lua grammar. Type
annotations, :: casts, continue, generics, compound assignment and string interpolation all
render wrong. DFP re-highlights with a tokenizer written for Luau.
It also marks deprecated APIs — the ones that make old answers actively harmful. A 2019 reply
recommending wait() and BodyVelocity still ranks on Google and still reads as authoritative.
Hovering a mark tells you what to use instead, sourced from Roblox's own API dump.
Hover any class, method, property or enum for its signature, parameters and a link to Creator Docs. All of it is bundled at build time — no request leaves your browser when you hover.
Code block controls add a language label, a soft-wrap toggle, copy-without-comments, and collapse for long blocks.
⌘K / Ctrl+K opens a palette: search topics, jump to any category, and apply Discourse's search
filters as one-click chips instead of remembering status:solved and min_posts:10.
Search results get age marks. Anything two years or older is flagged, because search is the one place you meet an old answer with no warning at all — on a sample query, 32 of 50 results were 2+ years old. Solved threads get a legible tick; stock renders it in the same grey as the lock icon.
Hover prefetch fetches a topic while you hover its link, so opening it is instant, and replays the real request in the background so your read state still records. A warm cache keeps recently-read bodies on disk.
- Topic lists mark solved, busy, closed and long-dormant threads
- Replies over two years old that recommend replaced APIs carry a quiet caution
- Thread view indents replies by depth, keeping chronological order so permalinks still work
- Quiet replies folds runs of "thanks", "+1" and "bump" into one line you can expand — never the opening post, an accepted answer, a reply someone answered, or anything with code
- Pin the opening post keeps it in a column beside the replies, scrolling on its own — off by default, on windows 1280px and wider
- Gated categories say so before you write the post, not at submit time
- Group chips — every group a member belongs to, with flair — on profiles, user cards and bylines
- Long "liked this" lists fold to twelve faces behind a
+N otherstoggle - Asset previews turn
rbxassetid://references and catalog links into real links, with a thumbnail fetched only when you hover one - Topic previews: hovering a link to another thread shows its title, whether it was solved and how old it is, from the same request DFP already makes to open a topic
- Creator Docs links get the hover card that API names in code already have. Reference pages (classes, datatypes, enums, libraries, globals) come from the bundled index with no request; a guide or tutorial page's title is read once, on hover, through the service worker — see Scope
- Chart theming repaints Discourse's own charts to match the theme
- Profile layout rebuilds the profile hero, stats and activity pages
- Similar topics surface as you type a title, so duplicates get caught
- A local draft vault survives a closed tab or a crash
- A Luau code-block button that tags the fence correctly
Five themes — dark, dim, black (OLED), light, off — times three densities times three
corner radii. Every colour derives from one OKLCH ramp, and every contrast and separation pair is
asserted at build time — over a thousand at the last generation; the exact count is written into
the header of tokens.generated.css each time it is built. A
regression fails the build rather than shipping.
Requires Node ≥ 20.11 (import.meta.dirname; 20.9 fails with a confusing paths[0] error).
A .nvmrc is checked in.
nvm use && npm install && npm run buildThen load it:
Download DevForumPlus-Chrome.zip or DevForumPlus-Firefox.zip from the
latest release and extract it. The asset names never change, so
updating is: extract over the same folder, then press reload in the browser. Keep the folder
path stable — Chrome derives the extension id from it, and a new folder is a new extension, which
resets settings, drafts and the topic cache.
Chromium — open chrome://extensions (or brave://extensions), enable Developer mode,
Load unpacked, select .output/chrome-mv3.
Firefox — run npx wxt build -b firefox, open about:debugging → This Firefox →
Load Temporary Add-on…, select .output/firefox-mv3/manifest.json. Firefox 128 is the floor:
world: "MAIN" content scripts landed there, and without one the extension cannot reach
Discourse's module loader at all. Firefox also treats host permissions as opt-in, so grant access
to devforum.roblox.com when prompted or nothing runs (create.roblox.com is asked for too; it only
feeds the Creator Docs hover cards, and everything else works without it).
Then open https://devforum.roblox.com.
The toolbar popup reports which boot rung engaged — the first thing to check if something looks off.
| Command | What it does |
|---|---|
npm run build |
Tokens → style checks → both targets to .output/ → gzip budgets |
npm run dev |
WXT dev server with hot reload |
npm run check |
Typecheck, style guardrails, unit tests |
npm run tokens |
Regenerate colours; fails the build on a contrast regression |
npm run harness |
Build .output/harness.html, the visual regression page |
It integrates with Discourse rather than scraping it. DevForum runs Discourse
3.5.0.beta3-dev and exposes withPluginApi (PLUGIN_API_VERSION 2.1.1), so DFP registers like a
theme component — value transformers, Glimmer outlets, decorateCookedElement.
The site's CSP (script-src 'nonce-…' 'strict-dynamic') forces two content scripts. An
isolated script cannot inject one into this page, so main-world.content.ts reaches Discourse's
module loader with no chrome.* access, and isolated.content.ts owns chrome.* and stamps
<html> before first paint. They talk over a MessageChannel; the isolated side treats the main
world as untrusted. There is no style-src, which is why the visual layer survives even if the JS
integration breaks.
Boot self-heals across three rungs — trapping window.define before the app boots, polling for
the plugin API after it, and finally CSS-only. A watchdog verifies rung 1 actually ran rather than
assuming it did.
Failures are contained. Every module install is wrapped and budgeted; one that runs over budget three routes running disables itself and says so in the popup. Nothing throws into Discourse.
The highest-leverage file is base.css, which retargets Discourse's own
custom properties at DFP tokens — one assignment restyles hundreds of rules across stylesheets we
never wrote a selector for. DFP's CSS is deliberately unlayered: Discourse's is too, and an
@layer always loses to unlayered rules regardless of specificity. npm run check:styles enforces
that, quarantines !important, and caps it.
No forum action is ever automated — no auto-like, reply, flag or vote, not behind a flag. Nothing is scraped into an external index. No analytics, no telemetry. Consent and age-verification scripts are never blocked, even optionally.
The palette's recent-topics list is the one record DFP keeps of what you read: the last twelve
topics this browser opened, in chrome.storage.local on this device only, never sent anywhere,
and cleared the moment the recent-topics module — or the palette, or DevForum Plus itself — is
switched off.
host_permissions is two origins, and the second is narrow. https://devforum.roblox.com/* is
where everything runs. https://create.roblox.com/* exists for one feature: a Creator Docs link in a
post gets a hover card naming the page, and that page sends no CORS headers, so only the service
worker can read it. The worker fetches nothing but /docs/… paths on that origin — the path is
checked against a fixed pattern and the URL rebuilt from a hardcoded origin, so a crafted link in
someone's post cannot point it anywhere else — with credentials: "omit", and only when you hover
the link. No tabs, cookies, webRequest, or <all_urls>.