Compare commits

...

2 commits

Author SHA1 Message Date
tomasalias
fed62b18bc docs: rewrite documentation and README in clear, direct developer tone
Some checks are pending
Build Windows Executable / Build BetterCurseForge.exe (push) Waiting to run
Deploy Documentation / build (push) Waiting to run
Deploy Documentation / deploy (push) Blocked by required conditions
2026-10-25 14:03:15 +01:00
tomasalias
862ed0f7d6 chore(docs): configure root base path and add Forgejo nav link 2026-10-25 13:38:11 +01:00
8 changed files with 205 additions and 201 deletions

2
.gitignore vendored
View file

@ -41,4 +41,6 @@ desktop.ini
tools/
update_icon.bat
update_icon.py
docs_for_claude.json

View file

@ -90,7 +90,7 @@ and `themes/my-theme.css`:
### Writing a plugin
A plugin lives in its own subfolder in `plugins/<plugin-name>/` with a `manifest.json`, an `index.js`, and an optional companion `styles.css`.
A plugin lives in its own subfolder, `plugins/<plugin-name>/`, with a `manifest.json`, an `index.js`, and optionally a `styles.css`.
`plugins/my-plugin/manifest.json`:
@ -121,10 +121,10 @@ plugin.onDisable = () => {
#### What plugins can do
- **UI & DOM tweaks.** Inject custom buttons, badges, links, or panels into CurseForge using standard DOM APIs. If a `styles.css` is present in the plugin folder, it is automatically injected when enabled and removed when disabled.
- **Method patching.** Intercept, modify, or override internal JavaScript functions with `BetterCurseForge.patcher.before()`, `after()`, or `instead()`.
- **Persistent settings.** Store and read user preferences across restarts using `BetterCurseForge.settings.get(key)` and `set(key, value)`.
- **Event listening.** Hook into application lifecycle events using `BetterCurseForge.on(event, callback)`.
- **UI and DOM tweaks.** Add buttons, badges, links or panels with the normal DOM APIs. If the plugin folder has a `styles.css`, it's injected when the plugin is enabled and removed when it's disabled.
- **Method patching.** Hook into or replace internal JavaScript functions with `BetterCurseForge.patcher.before()`, `after()` or `instead()`.
- **Persistent settings.** Save and read preferences across restarts with `BetterCurseForge.settings.get(key)` and `set(key, value)`.
- **Events.** Listen for app lifecycle events with `BetterCurseForge.on(event, callback)`.
## Building from source
@ -142,7 +142,7 @@ The executable ends up in `dist/BetterCurseForge.exe`.
### Syncing changes from GitHub
To pull down updates made on GitHub:
To pull changes from GitHub:
```powershell
git pull origin master

View file

@ -3,13 +3,13 @@ import { defineConfig } from 'vitepress';
export default defineConfig({
title: 'BetterCurseForge',
description: 'Client mod for CurseForge Launcher',
base: process.env.BASE_URL || '/BetterCurseForge/',
base: process.env.BASE_URL || '/',
appearance: 'dark',
lastUpdated: true,
cleanUrls: true,
head: [
['link', { rel: 'icon', type: 'image/png', href: (process.env.BASE_URL || '/BetterCurseForge/') + 'logo.png' }],
['link', { rel: 'icon', type: 'image/png', href: (process.env.BASE_URL || '/') + 'logo.png' }],
['meta', { name: 'theme-color', content: '#9333ea' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:title', content: 'BetterCurseForge' }],
@ -23,6 +23,7 @@ export default defineConfig({
nav: [
{ text: 'Guide', link: '/guide/installation' },
{ text: 'API', link: '/api/' },
{ text: 'Forgejo', link: 'http://92.5.113.44:3000/tomasalias/BetterCurseForge' },
{ text: 'GitHub', link: 'https://github.com/tomasalias/BetterCurseForge' },
],

View file

@ -1,12 +1,12 @@
# API Reference
BetterCurseForge exposes a global runtime object on `window.BetterCurseForge` within the CurseForge Electron renderer process. This API allows themes, plugins, and developer scripts to inject styles, monkey-patch methods, manage settings, and listen to application events.
BetterCurseForge adds a global object, `window.BetterCurseForge`, to CurseForge's Electron renderer process. Themes, plugins and your own scripts can use it to inject styles, patch methods, read and write settings, and listen for events.
---
## TypeScript Definition
## TypeScript definitions
For TypeScript development and autocompletion:
If you're using TypeScript, this gives you types and autocompletion:
```typescript
declare global {
@ -54,7 +54,7 @@ export interface BetterCurseForgeAPI {
### `BetterCurseForge.version`
- **Type**: `string`
- **Description**: The currently running BetterCurseForge runtime version.
- **Description**: Version of the BetterCurseForge runtime that's currently running.
```javascript
console.log(BetterCurseForge.version); // "1.0.0"
@ -64,11 +64,11 @@ console.log(BetterCurseForge.version); // "1.0.0"
### `BetterCurseForge.injectCSS(css)`
Dynamically injects CSS rules into the document `<head>`.
Adds CSS rules to the document `<head>`.
- **Parameters**:
- `css` *(string)*: Raw CSS string to inject.
- **Returns**: `() => void` — Function that removes the injected `<style>` tag when called.
- `css` *(string)*: The CSS to inject.
- **Returns**: `() => void`. Call it to remove the injected `<style>` tag.
```javascript
// Inject styles
@ -86,15 +86,15 @@ uninject();
## Settings API (`BetterCurseForge.settings`)
Manages persistent configuration stored in `%APPDATA%\CurseForge\BetterCurseForge\settings.json`.
Persistent configuration, stored in `%APPDATA%\CurseForge\BetterCurseForge\settings.json`.
### `settings.get(key?)`
Retrieves a setting by key, or returns the entire settings object if no key is specified.
Returns the setting for `key`, or the whole settings object if you don't pass a key.
- **Parameters**:
- `key` *(string, optional)*: Setting key name.
- **Returns**: `Promise<any>` — Value of the setting, or `null`.
- `key` *(string, optional)*: Name of the setting.
- **Returns**: `Promise<any>`. The value, or `null` if it isn't set.
```javascript
// Retrieve a specific value
@ -106,12 +106,12 @@ const allSettings = await BetterCurseForge.settings.get();
### `settings.set(key, value)`
Stores a setting value and writes it asynchronously to disk.
Saves a value and writes it to disk asynchronously.
- **Parameters**:
- `key` *(string)*: Setting key name.
- `value` *(any)*: JSON-serializable value.
- **Returns**: `Promise<boolean>` — `true` if saved successfully.
- `key` *(string)*: Name of the setting.
- `value` *(any)*: Any JSON-serializable value.
- **Returns**: `Promise<boolean>`. `true` if the save worked.
```javascript
await BetterCurseForge.settings.set('myPlugin.fontSize', 14);
@ -121,17 +121,17 @@ await BetterCurseForge.settings.set('myPlugin.fontSize', 14);
## Patcher API (`BetterCurseForge.patcher`)
Provides monkey-patching utilities to inspect, modify, or replace methods on JavaScript objects and modules safely.
Utilities for inspecting, modifying or replacing methods on JavaScript objects and modules. Every function returns an unpatch function.
### `patcher.before(obj, method, callback)`
Executes `callback(args)` **before** the target method is invoked.
Runs `callback(args)` **before** the target method is called.
- **Parameters**:
- `obj` *(object)*: Target object.
- `method` *(string)*: Method name on `obj`.
- `callback` *(Function)*: Function receiving arguments: `(args) => void`.
- **Returns**: `() => void` — Unpatch function that restores the original method.
- `callback` *(Function)*: `(args) => void`.
- **Returns**: `() => void`. Call it to restore the original method.
```javascript
const unpatch = BetterCurseForge.patcher.before(console, 'warn', (args) => {
@ -146,13 +146,13 @@ unpatch();
### `patcher.after(obj, method, callback)`
Executes `callback(args, result)` **after** the target method runs. You can return a new value to replace the method's return value.
Runs `callback(args, result)` **after** the target method. Return a value to replace the method's return value.
- **Parameters**:
- `obj` *(object)*: Target object.
- `method` *(string)*: Method name on `obj`.
- `callback` *(Function)*: `(args, result) => any`.
- **Returns**: `() => void` — Unpatch function.
- **Returns**: `() => void`. Unpatch function.
```javascript
const unpatch = BetterCurseForge.patcher.after(service, 'getTitle', (args, result) => {
@ -166,13 +166,13 @@ unpatch();
### `patcher.instead(obj, method, callback)`
Completely overrides the target method. Receives both the incoming arguments and a reference to the original method.
Replaces the target method. The callback gets the arguments and a reference to the original method.
- **Parameters**:
- `obj` *(object)*: Target object.
- `method` *(string)*: Method name on `obj`.
- `callback` *(Function)*: `(args, originalFn) => any`.
- **Returns**: `() => void` — Unpatch function.
- **Returns**: `() => void`. Unpatch function.
```javascript
const unpatch = BetterCurseForge.patcher.instead(target, 'openExternalUrl', (args, originalFn) => {
@ -188,12 +188,12 @@ unpatch();
---
## Event System (`BetterCurseForge.on / off / emit`)
## Event system (`BetterCurseForge.on / off / emit`)
BetterCurseForge includes an event bus for inter-plugin and lifecycle communication.
BetterCurseForge has an event bus that plugins can use to talk to each other and to react to lifecycle events.
### `BetterCurseForge.on(event, callback)`
Subscribes a listener to an event.
Adds a listener for an event.
```javascript
const onReady = () => console.log('BetterCurseForge is ready!');
@ -201,14 +201,14 @@ BetterCurseForge.on('ready', onReady);
```
### `BetterCurseForge.off(event, callback)`
Unsubscribes a listener.
Removes a listener.
```javascript
BetterCurseForge.off('ready', onReady);
```
### `BetterCurseForge.emit(event, ...args)`
Emits an event to all registered listeners.
Calls every listener registered for the event.
```javascript
BetterCurseForge.emit('custom-event', { detail: 123 });
@ -216,10 +216,10 @@ BetterCurseForge.emit('custom-event', { detail: 123 });
---
## Subsystem Managers
## Subsystem managers
### `BetterCurseForge.themes` (`ThemeManager`)
Provides programmatic control over custom themes:
Control custom themes from code:
```javascript
// Get all discovered themes
@ -242,7 +242,7 @@ BetterCurseForge.themes.removeTheme(true);
```
### `BetterCurseForge.plugins` (`PluginManager`)
Provides programmatic control over plugins:
Control plugins from code:
```javascript
// Get all installed plugins
@ -253,7 +253,7 @@ await BetterCurseForge.plugins.togglePlugin('compact-mode');
```
### `BetterCurseForge.ads` (`AdBlocker`)
Internal ad blocker runtime:
The internal ad blocker runtime:
```javascript
// Contains zero-ad CSS rules and ad container cleanup handlers

View file

@ -1,51 +1,51 @@
# Installation & Usage
This guide covers installing, managing, and uninstalling **BetterCurseForge** using either the desktop GUI application or the command-line interface.
How to install, check, and remove **BetterCurseForge**, using either the desktop app or the command line.
---
## Prerequisites
Before using BetterCurseForge, make sure you have:
You need:
- **Windows 10 or Windows 11** (64-bit)
- **CurseForge Launcher** installed (standalone or Overwolf edition)
- CurseForge closed before running the patcher
- CurseForge closed when you run the patcher
::: tip SAFE & 100% REVERSIBLE
Before modifying any files, BetterCurseForge creates untouched vanilla backups at `resources/app.asar.vanilla` and `CurseForge.exe.vanilla`. You can cleanly revert to stock CurseForge at any time with a single click.
::: tip BACKUPS
Before it changes anything, BetterCurseForge saves untouched copies of the original files at `resources/app.asar.vanilla` and `CurseForge.exe.vanilla`. You can go back to stock CurseForge whenever you want, with one click.
:::
---
## Method 1: Using the Desktop GUI (Recommended)
## Option 1: Desktop GUI (recommended)
BetterCurseForge comes as a standalone desktop executable with a sleek, dark-themed graphical interface.
BetterCurseForge is a single executable with a dark-themed GUI.
### Step 1: Download `BetterCurseForge.exe`
Download the latest executable from the official releases:
Grab the latest build from the releases page:
- [Download `BetterCurseForge.exe`](https://github.com/tomasalias/BetterCurseForge/releases/latest)
Place it in any convenient folder (e.g., Downloads, Tools, or desktop).
Put it anywhere you like (Downloads, a tools folder, the desktop).
### Step 2: Open BetterCurseForge
Double-click `BetterCurseForge.exe` to launch the application.
Double-click `BetterCurseForge.exe` to open it.
![BetterCurseForge GUI](/logo.png){width=64 style="display:block;margin:1rem auto;"}
The application automatically:
- Detects your CurseForge installation folder from the Windows Registry.
- Checks whether your client is currently vanilla or patched.
- Displays the installed CurseForge version and installation directory.
On startup it:
- Finds your CurseForge install folder through the Windows Registry.
- Checks whether CurseForge is vanilla or patched.
- Shows the installed CurseForge version and install directory.
### Step 3: Click "Patch CurseForge"
1. Click the **Patch CurseForge** button.
2. The patcher will close any running CurseForge processes, create a vanilla backup, apply all enhancements (ad removal, theme engine, premium unlocks, and plugin loader), update the executable integrity signature, and repack the application.
3. You will see live output in the log panel confirming:
2. The patcher closes any running CurseForge processes, backs up the vanilla files, applies the patch (ad blocking, theme engine, skin unlocks, plugin loader), updates the integrity signature in the executable, and repacks the app.
3. The log panel shows progress as it goes:
```text
[+] Found CurseForge at: C:\Users\Username\AppData\Local\Programs\CurseForge Windows
[+] Unlocked native premium themes (2 route checks)
@ -60,17 +60,17 @@ The application automatically:
[+] Auto-repatch watcher active and persistent across updates.
[*] CurseForge successfully patched! Ads removed, themes & plugins enabled.
```
4. Click **Launch CurseForge** or open your usual desktop shortcut—you're done!
4. Click **Launch CurseForge** or start it from your usual shortcut. That's it.
---
## Method 2: Command-Line Interface (CLI)
## Option 2: Command line
For automated workflows, scripting, or headless environments, `BetterCurseForge.exe` provides a comprehensive CLI:
If you want to script it or run it without the GUI, `BetterCurseForge.exe` has a CLI.
### Patching via Terminal
### Patching
Open PowerShell or Command Prompt in the folder containing `BetterCurseForge.exe`:
Open PowerShell or Command Prompt in the folder with `BetterCurseForge.exe`:
::: code-group
@ -84,9 +84,9 @@ BetterCurseForge.exe patch
:::
### Checking Status
### Checking status
Verify whether your client is patched:
See whether CurseForge is patched:
```powershell
.\BetterCurseForge.exe status
@ -101,26 +101,26 @@ ASAR Hash: Verified
### Unpatching
Restore your vanilla CurseForge client:
Go back to stock CurseForge:
```powershell
.\BetterCurseForge.exe unpatch
```
This restores `resources/app.asar` from the vanilla backup and re-verifies original executable signatures.
This restores `resources/app.asar` from the vanilla backup and re-verifies the original executable signatures.
---
## Auto-Repatch: Surviving CurseForge Updates
## Auto-repatch after CurseForge updates
When the official CurseForge Launcher downloads an automatic update, it overwrites `app.asar` with an unpatched version and attempts to restart.
When CurseForge updates itself, it overwrites `app.asar` with a stock copy and restarts.
BetterCurseForge provides an autonomous, smooth transition with **zero screen flashing**:
BetterCurseForge handles this without the unpatched launcher ever showing up on screen.
### Managing Auto-Repatch in the GUI
- In the BetterCurseForge desktop application, simply toggle the **Auto-Repatch on Update** button (turns green when active).
### Managing it in the GUI
- Toggle the **Auto-Repatch on Update** button in the app. It turns green when it's on.
### Managing Auto-Repatch via CLI
### Managing it from the CLI
```powershell
# Run the background watcher daemon directly:
.\BetterCurseForge.exe watch
@ -133,18 +133,18 @@ BetterCurseForge provides an autonomous, smooth transition with **zero screen fl
.\BetterCurseForge.exe unpatch # Restores vanilla client and stops watcher
```
### How Auto-Repatch Works
1. **Background Watcher**: Runs silently with 0% CPU consumption via Windows directory event notifications and heartbeat checks.
2. **Active Vanilla Interceptor**: When an update or unpatched state is detected, the patcher polls every 150ms using Win32 kernel process enumeration. If the installer launches `CurseForge.exe`, it is killed within 50ms before any window or frame can appear.
3. **Dedicated Splash Updater GUI**: A modern, dark-themed `#121214` card appears on screen displaying the application icon, a purple `AUTO-UPDATE` badge, an animated progress bar, and real-time status messages while extracting, unlocking themes, removing ads, and repacking.
4. **Offline Zero-Delay Engine**: Offline ASAR extraction and repacking complete in 2–3 seconds using CurseForge's built-in Node v24 runtime (`ELECTRON_RUN_AS_NODE=1`), synchronizing the `OWEASARSIG` hash directly inside `CurseForge.exe`.
5. **Seamless Relaunch**: The patched BetterCurseForge client opens automatically, and the splash window gracefully closes.
### How it works
1. **Background watcher**: Runs in the background on Windows directory change notifications and periodic heartbeat checks, so CPU use is negligible.
2. **Killing the stock launcher**: Once it sees an update or an unpatched install, the watcher polls every 150 ms with Win32 process enumeration. If the installer starts `CurseForge.exe`, the watcher kills it within 50 ms, before a window can appear.
3. **Splash window**: A dark `#121214` card shows the app icon, a purple `AUTO-UPDATE` badge, a progress bar, and status messages while it extracts, unlocks themes, blocks ads and repacks.
4. **Offline repatch**: Extracting and repacking the ASAR takes 2–3 seconds and needs no internet. It uses the Node v24 runtime bundled with CurseForge (`ELECTRON_RUN_AS_NODE=1`) and writes the new `OWEASARSIG` hash into `CurseForge.exe`.
5. **Relaunch**: The patched CurseForge opens and the splash window closes.
---
## How It Works Under the Hood
## Under the hood
Modern versions of CurseForge include **ASAR Code Integrity Verification** enforced directly inside `CurseForge.exe`:
Recent CurseForge versions verify the integrity of `app.asar` from inside `CurseForge.exe`. This is the patch flow:
```mermaid
flowchart TD
@ -158,19 +158,19 @@ flowchart TD
H --> I["Launch Modded CurseForge with Full Permissions"]
```
1. **Multi-Layer Ad Elimination**: Blocks ad network requests at the Electron session level (`session.webRequest`) and collapses ad frames to 0px using CSS rules, completely preserving React Fiber virtual DOM reconciliation.
2. **Premium Skin Unlock**: Uses version-resilient AST/regex matching to unlock all official CurseForge skins (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Halloween*, etc.) in **Settings -> Themes**.
3. **ASAR Signature Synchronization**: Calculates the cryptographic SHA256 hash of the modified ASAR archive header and writes the new signature directly into `CurseForge.exe`, ensuring Electron boots without security errors or corruption alerts.
1. **Ad blocking**: Ad requests are blocked at the Electron session level (`session.webRequest`), and CSS collapses the ad frames to 0px. The elements stay in the DOM, so React Fiber's reconciliation isn't affected.
2. **Skin unlock**: AST and regex matching, written to tolerate version changes, unlocks the official CurseForge skins (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Halloween*, etc.) in **Settings -> Themes**.
3. **ASAR signature update**: It computes the SHA256 hash of the modified ASAR header and writes it into `CurseForge.exe`, so Electron starts without integrity errors.
---
## Troubleshooting & FAQ
## Troubleshooting
::: details How do I verify BetterCurseForge is running?
::: details How do I tell it's working?
1. Open CurseForge.
2. Notice the total absence of banner ads and video sponsor frames.
3. Navigate to **Settings -> Themes**: you will see the **Client Themes** section with *Purple Night* available, as well as unlocked *Premium* skins (*Pixelforge*, *Lifeforge*, etc.).
4. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> to open DevTools. The console will display:
2. There should be no banner ads or video sponsor frames.
3. Go to **Settings -> Themes**. You should see a **Client Themes** section with *Purple Night* in it, and the *Premium* skins (*Pixelforge*, *Lifeforge*, etc.) unlocked.
4. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> to open DevTools. The console should print:
```text
[BetterCF] Initializing renderer runtime...
[BetterCF] Theme manager ready (1 theme(s) found). Active: purple-night.css
@ -178,10 +178,10 @@ flowchart TD
```
:::
::: details Antivirus false-positive warning
Because `BetterCurseForge.exe` inspects running processes (`CurseForge.exe`), accesses the Windows Registry to locate install paths, and updates executable hashes, some heuristic scanners may flag it. BetterCurseForge is completely open source and safe. You can inspect the entire Python codebase in `patcher/` and build it yourself.
::: details Antivirus flags the exe
Some antivirus tools flag `BetterCurseForge.exe` as a false positive. It looks at running processes (`CurseForge.exe`), reads the Windows Registry to find the install path, and rewrites hashes in an executable, which is the kind of thing heuristic scanners react to. The project is open source: the Python code is in `patcher/`, and you can read it and build the exe yourself.
:::
::: details Permission denied / EPERM error
If your CurseForge launcher is installed under `C:\Program Files`, modifying files requires Administrator permissions. Right-click `BetterCurseForge.exe` and select **Run as Administrator**.
If CurseForge is installed under `C:\Program Files`, the patcher needs Administrator permissions to change files. Right-click `BetterCurseForge.exe` and choose **Run as Administrator**.
:::

View file

@ -1,18 +1,18 @@
# Writing Plugins
BetterCurseForge features a lightweight plugin system that allows you to extend CurseForge Launcher functionality, manipulate the DOM, hook runtime methods, and persist configuration.
Plugins are small JavaScript modules that run inside CurseForge. They can change the DOM, patch methods at runtime, and save settings between sessions.
---
## Plugin Directory Structure
## Plugin folder
Plugins are stored in the BetterCurseForge user directory:
Plugins live in the BetterCurseForge user directory:
```text
%APPDATA%\CurseForge\BetterCurseForge\plugins\
```
Each plugin lives in its own dedicated subfolder:
Each plugin gets its own subfolder:
```text
plugins/
@ -22,13 +22,13 @@ plugins/
└── styles.css # Optional: Companion stylesheet
```
You can open the plugins folder directly from the BetterCurseForge desktop GUI by clicking **Open Plugins Folder**.
The **Open Plugins Folder** button in the desktop app opens it.
---
## Plugin Manifest (`manifest.json`)
## Manifest (`manifest.json`)
The `manifest.json` file declares your plugin's metadata:
`manifest.json` describes the plugin:
```json
{
@ -42,22 +42,22 @@ The `manifest.json` file declares your plugin's metadata:
}
```
### Manifest Fields
### Fields
| Field | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| `name` | `string` | **Yes** | Display name shown in the management UI. |
| `version` | `string` | **Yes** | Semantic version string (e.g. `1.0.0`). |
| `description` | `string` | No | Brief summary of what the plugin accomplishes. |
| `name` | `string` | **Yes** | Name shown in the management UI. |
| `version` | `string` | **Yes** | Semantic version (e.g. `1.0.0`). |
| `description` | `string` | No | Short summary of what the plugin does. |
| `author` | `string` | No | Author name or handle. |
| `main` | `string` | No | Entry JavaScript file. Defaults to `index.js`. |
| `styles` | `string` | No | Companion stylesheet injected automatically on enable. Defaults to `styles.css`. |
| `main` | `string` | No | Entry script. Defaults to `index.js`. |
| `styles` | `string` | No | Stylesheet that's injected automatically when the plugin is enabled. Defaults to `styles.css`. |
---
## Plugin Lifecycle & Execution
## Lifecycle
Plugin scripts are executed when enabled, receiving the `BetterCurseForge` global API and a `plugin` context object:
A plugin's script runs when the plugin is enabled. It gets the `BetterCurseForge` API and a `plugin` context object:
```javascript
// index.js
@ -73,16 +73,16 @@ plugin.onDisable = () => {
};
```
::: tip AUTOMATIC STYLE INJECTION & REMOVAL
If your plugin folder contains a `styles.css` (or file declared in `"styles"` in `manifest.json`), BetterCurseForge automatically injects it into `<head>` when your plugin is enabled and removes it when disabled! You do not need to manually inject or clean up companion stylesheets.
::: tip STYLESHEETS
If your plugin folder has a `styles.css` (or the file named in `"styles"` in `manifest.json`), BetterCurseForge injects it into `<head>` when the plugin is enabled and removes it when the plugin is disabled. You don't need to inject or clean it up yourself.
:::
---
## BetterCurseForge Plugin APIs
## Plugin API
### 1. `BetterCurseForge.injectCSS(css)`
Injects custom CSS dynamically into `<head>`. Returns a cleanup function that unmounts the style tag:
Injects CSS into `<head>`. Returns a function that removes the style tag:
```javascript
const removeStyles = BetterCurseForge.injectCSS(`
@ -98,7 +98,7 @@ plugin.onDisable = () => {
---
### 2. `BetterCurseForge.settings`
Stores and retrieves persistent settings saved to disk (`settings.json`):
Reads and writes settings that are saved to disk (`settings.json`):
```javascript
// Retrieve a stored setting (or null if not set)
@ -111,10 +111,10 @@ await BetterCurseForge.settings.set('compactMode.density', 'ultra');
---
### 3. `BetterCurseForge.patcher`
Safe method monkey-patching for objects and functions:
Helpers for monkey-patching methods on objects. Each call returns a function that undoes the patch:
#### `patcher.before(object, methodName, callback)`
Runs your callback before the target method executes. Receives `(args)`:
Runs your callback before the original method. The callback gets `(args)`:
```javascript
const unpatch = BetterCurseForge.patcher.before(console, 'error', (args) => {
@ -125,7 +125,7 @@ plugin.onDisable = () => unpatch();
```
#### `patcher.after(object, methodName, callback)`
Runs after the target method completes. Receives `(args, result)`. You can return a modified value:
Runs after the original method. The callback gets `(args, result)` and can return a new value to replace the result:
```javascript
const unpatch = BetterCurseForge.patcher.after(targetObj, 'getItemTitle', (args, result) => {
@ -136,7 +136,7 @@ plugin.onDisable = () => unpatch();
```
#### `patcher.instead(object, methodName, callback)`
Completely supersedes the target method. Receives `(args, originalMethod)`:
Replaces the original method. The callback gets `(args, originalMethod)`:
```javascript
const unpatch = BetterCurseForge.patcher.instead(targetObj, 'fetchData', (args, originalFn) => {
@ -150,7 +150,7 @@ plugin.onDisable = () => unpatch();
---
### 4. `BetterCurseForge.on(event, callback)` / `.off()` / `.emit()`
Application-wide event emitter:
An event emitter shared across the app:
```javascript
const onReady = () => console.log('CurseForge UI is fully loaded!');
@ -164,9 +164,9 @@ plugin.onDisable = () => {
---
## Complete Example: Compact Mode Plugin
## Example: Compact Mode
This plugin adds a high-density layout mode to CurseForge.
This plugin makes CurseForge's layout denser.
::: code-group

View file

@ -1,33 +1,33 @@
# Custom Themes & Theming Guide
# Themes
BetterCurseForge features a native, live-reloading theming engine. Themes allow you to completely restyle the CurseForge Launcher using standard CSS and theme manifests, fully integrated into the official user interface.
BetterCurseForge can load custom themes and reload them live. A theme is a CSS file, optionally with a JSON manifest, and it appears in CurseForge's own theme settings.
---
## In-App Theme Selector
## Picking a theme
BetterCurseForge embeds client themes directly into CurseForge's native **Settings -> Themes** menu.
Client themes are added to CurseForge's own **Settings -> Themes** page.
### How to Access Client Themes
1. Open CurseForge Launcher.
### Finding client themes
1. Open CurseForge.
2. Click the **Settings** gear icon in the bottom-left corner.
3. Select **Themes** from the settings sidebar.
4. Scroll down past the *Classic*, *Colorblind*, and *Premium* categories to find the **Client Themes** section:
3. Choose **Themes** in the settings sidebar.
4. Scroll past the *Classic*, *Colorblind* and *Premium* categories to reach **Client Themes**:
![Settings Themes View](/logo.svg){width=48 style="display:block;margin:1rem auto;"}
### Native Features in Settings -> Themes
- **Live Hover Preview**: Hovering your cursor over any theme card immediately previews the theme across the entire launcher in real time. Move your cursor away to revert, or click to apply.
- **Mutual Exclusivity**: Selecting a client theme seamlessly deselects native skins, and vice versa. Only one theme is active at a time.
- **"Open Folder" Button**: Directly opens your themes folder in Windows Explorer so you can drop in new stylesheets.
- **"Refresh" Button**: Reloads all installed custom themes from disk instantly without needing to restart CurseForge.
- **Native Premium Themes Unlocked**: All official CurseForge Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, and *Spookyforge*) are permanently unlocked and free to use!
### What the theme page does
- **Hover preview**: Hover over a theme card to preview it across the whole launcher. Move the cursor away to revert, or click to apply it.
- **One theme at a time**: Picking a client theme deselects any native skin, and the other way around.
- **Open Folder button**: Opens your themes folder in Explorer so you can drop in new stylesheets.
- **Refresh button**: Reloads your custom themes from disk, no restart needed.
- **Premium themes unlocked**: The official Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge* and *Spookyforge*) are unlocked and free to use.
---
## Theme Folder Location
## Theme folder
Themes are stored in your user application data directory:
Themes live in your user application data directory:
```text
%APPDATA%\CurseForge\BetterCurseForge\themes\
@ -38,16 +38,16 @@ Full path:
C:\Users\<YourUsername>\AppData\Roaming\CurseForge\BetterCurseForge\themes\
```
You can open this folder anytime by clicking the **Open Folder** button in **Settings -> Themes**.
The **Open Folder** button in **Settings -> Themes** opens it for you.
---
## Theme File Structure
## Theme layout
BetterCurseForge supports two convenient formats:
There are two ways to lay out a theme:
### 1. Single-File Theme (Recommended)
Place a `.css` file in the `themes/` directory, with an optional accompanying `.json` manifest:
### 1. Single file (recommended)
Put a `.css` file in `themes/`, with an optional `.json` manifest next to it:
```text
themes/
@ -55,8 +55,8 @@ themes/
└── purple-night.json (optional metadata & preview colors)
```
### 2. Folder-Based Theme
Create a folder inside `themes/` with a `theme.css` and `theme.json`:
### 2. Folder
Make a folder inside `themes/` containing `theme.css` and `theme.json`:
```text
themes/
@ -68,9 +68,9 @@ themes/
---
## Theme Manifest Format (`theme.json`)
## Manifest (`theme.json`)
A `.json` manifest provides metadata and defines the miniature preview card colors shown in the **Settings -> Themes** menu:
The manifest holds the theme's metadata and the colors of the small preview card shown in **Settings -> Themes**:
```json
{
@ -85,78 +85,78 @@ A `.json` manifest provides metadata and defines the miniature preview card colo
}
```
### Manifest Fields
### Fields
| Field | Type | Description |
| :--- | :--- | :--- |
| `name` | `string` | Display name shown on the theme card and in settings. |
| `version` | `string` | Semantic version string (e.g. `1.0.0`). |
| `description` | `string` | Short tooltip description displayed when hovering the title. |
| `name` | `string` | Name shown on the theme card and in settings. |
| `version` | `string` | Semantic version (e.g. `1.0.0`). |
| `description` | `string` | Short description, shown as a tooltip when you hover the title. |
| `author` | `string` | Author name or handle. |
| `primaryColor` | `string` | Hex color for the primary square icon in the thumbnail card. |
| `titleColor` | `string` | Hex color for the top bar in the thumbnail card. |
| `bodyColor` | `string` | Hex color for the lower text bar in the thumbnail card. |
| `backgroundColor`| `string` | Hex background color for the thumbnail card itself. |
| `primaryColor` | `string` | Hex color of the square icon on the preview card. |
| `titleColor` | `string` | Hex color of the top bar on the preview card. |
| `bodyColor` | `string` | Hex color of the lower text bar on the preview card. |
| `backgroundColor`| `string` | Hex background color of the preview card. |
---
## CurseForge CSS Variables Reference
## CSS variables
CurseForge is styled using CSS Custom Properties (variables). Overriding these variables allows you to theme 95% of the application cleanly without touching individual class names.
CurseForge is styled with CSS custom properties. Overriding them lets you theme most of the app without touching individual class names.
### Brand & Accents
### Brand & accents
| Variable | Description |
| :--- | :--- |
| `--surface-brand-brand` | Primary brand accent (active tabs, primary buttons, indicators). |
| `--surface-brand-brand` | Main brand accent: active tabs, primary buttons, indicators. |
| `--surface-brand-brand-hover` | Hover state for brand-colored elements. |
| `--color-primary` | Main accent color. |
| `--color-accent` | Secondary highlight color. |
| `--selected-item-border` | Border style for selected items and active inputs. |
### Surfaces & Backgrounds
### Surfaces & backgrounds
| Variable | Description |
| :--- | :--- |
| `--color-background` | Main application background (content views, modpack library). |
| `--color-background` | Main app background (content views, modpack library). |
| `--surface-base` | Darkest background layer (scroll tracks, container bases). |
| `--surface-primary` | Elevated primary surface (sidebars, sub-panels). |
| `--surface-secondary` | Secondary surface layer (navigation menus, dialog panels). |
| `--surface-tertiery` | Tertiary surface layer (mod cards, list row containers). |
| `--surface-on-surface` | Subtle translucent overlay for buttons (`rgba(...)`). |
| `--surface-primary` | Raised surface (sidebars, sub-panels). |
| `--surface-secondary` | Second surface layer (navigation menus, dialog panels). |
| `--surface-tertiery` | Third surface layer (mod cards, list row containers). |
| `--surface-on-surface` | Faint translucent overlay for buttons (`rgba(...)`). |
| `--surface-on-surface-hover` | Translucent hover overlay for buttons. |
### Modpack & Library Cards
### Modpack & library cards
| Variable | Description |
| :--- | :--- |
| `--surface-card` | Modpack / project card base background. |
| `--surface-card-hover` | Background color when hovering over modpack cards. |
| `--color-surface-card-active` | Active or clicked state for card items. |
| `--surface-card` | Base background of modpack and project cards. |
| `--surface-card-hover` | Background when hovering over a modpack card. |
| `--color-surface-card-active` | Active or clicked state of a card. |
### Typography & Text
### Typography & text
| Variable | Description |
| :--- | :--- |
| `--text-pure` | Pure white text (`#ffffff`). |
| `--text-primary` | Primary readable text color. |
| `--text-primary` | Main readable text color. |
| `--color-text-title` | Headings, modpack titles, section names. |
| `--color-text-body` | Standard body and description text. |
| `--color-text-body` | Normal body and description text. |
| `--color-text-secondary` | Subtitles, authors, version numbers. |
### Title Bar & Navigation
### Title bar & navigation
| Variable | Description |
| :--- | :--- |
| `--title-bar-background` | Background color or gradient for the top window title bar. |
| `--btn-window-action` | Minimize, maximize, and close button icons. |
| `--color-scrollbar-thumb` | Scrollbar thumb handle color. |
| `--title-bar-background` | Background color or gradient of the window title bar. |
| `--btn-window-action` | Icons on the minimize, maximize and close buttons. |
| `--color-scrollbar-thumb` | Scrollbar thumb color. |
---
## Example Theme: Emerald Night
## Example: Emerald Night
Here is a complete, working theme stylesheet you can save as `emerald-night.css`:
A full working theme. Save the stylesheet as `emerald-night.css` and the manifest as `emerald-night.json`:
::: code-group
@ -237,12 +237,12 @@ button[class*="primary"]:not([class*="secondary"]):hover {
---
## Tips for Inspecting Elements
## Inspecting elements
Because CurseForge runs on Electron and React, you can inspect any UI element using Chromium DevTools:
CurseForge is an Electron and React app, so you can inspect its UI with Chromium DevTools:
1. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>I</kbd> in CurseForge to open DevTools.
2. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> to activate the element inspector.
3. Click on any button, banner, header, or list item to reveal its computed styles and classes in the **Elements** panel.
4. Test CSS changes live in the **Styles** tab before adding them to your theme file.
5. In **Settings -> Themes**, click **Refresh** to instantly apply your modified theme stylesheet!
2. Press <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>C</kbd> to turn on the element inspector.
3. Click a button, banner, header or list item to see its computed styles and classes in the **Elements** panel.
4. Try CSS changes in the **Styles** tab before adding them to your theme.
5. In **Settings -> Themes**, click **Refresh** to load your updated stylesheet.

View file

@ -3,8 +3,8 @@ layout: home
hero:
name: "BetterCurseForge"
text: "Client mod for CurseForge Launcher"
tagline: "Ad-free experience, custom themes, unlocked premium skins, and plugins."
text: "A client mod for the CurseForge launcher"
tagline: "Ad blocking, custom themes, unlocked premium skins, and plugins."
image:
src: /logo.png
alt: BetterCurseForge
@ -18,30 +18,30 @@ hero:
features:
- icon: 🚫
title: Complete Ad Removal
details: Multi-layer elimination (zero-ad CSS rules, network-level request blocking, and layout collapsing) removes all video ads, banners, and empty containers without disrupting React reconciliation.
title: Ad blocking
details: Ad requests are blocked at the network level, and CSS rules collapse the video ads, banners and empty containers that are left. The elements stay in the DOM, so React keeps working.
- icon: 🎨
title: Client Themes & Free Skins
details: Integrated directly into Settings -> Themes with live hover previews, theme folder shortcuts, and all native CurseForge Premium themes unlocked for free.
title: Themes and free skins
details: Client themes show up in Settings -> Themes with live hover previews and a shortcut to the themes folder. The official premium skins are unlocked too.
- icon: 🔄
title: Auto-Repatch & Smooth Updates
details: Survives launcher updates effortlessly. The active interceptor suppresses unpatched windows, and a sleek splash GUI displays live progress while repatching in seconds.
title: Auto-repatch after updates
details: When the launcher updates, BetterCurseForge stops the unpatched copy from opening, shows a small splash window with progress, and repatches in a few seconds.
- icon: 🖥️
title: Modern GUI & CLI
details: Includes an intuitive dark-themed desktop application with one-click actions, as well as a full command-line interface for power users.
title: GUI and CLI
details: A dark-themed desktop app with one-click actions, plus a command-line interface for scripting.
- icon: 🧩
title: Plugin System
details: Extend launcher capabilities with lightweight JavaScript plugins using our runtime monkey-patcher and persistent settings API.
title: Plugins
details: Write small JavaScript plugins that patch methods at runtime and keep their settings between restarts.
- icon: 🛡️
title: Safe & 100% Reversible
details: Automatically creates clean vanilla backups (`app.asar.vanilla` and `CurseForge.exe.vanilla`). You can restore stock CurseForge at any time with a single click.
title: Backups and unpatching
details: Original files are backed up first (`app.asar.vanilla` and `CurseForge.exe.vanilla`), and you can restore stock CurseForge with one click.
---
<div class="quickstart-section" style="margin-top: 3rem; text-align: center;">
## Quick Start
Download `BetterCurseForge.exe` and patch in one click:
Download `BetterCurseForge.exe`, then open it for the GUI or patch from a terminal:
```bash
# Launch the desktop GUI:
@ -57,14 +57,15 @@ BetterCurseForge.exe patch
## Why BetterCurseForge?
CurseForge is the premier platform for Minecraft modpacks, World of Warcraft addons, and game mods, but the official desktop app is burdened with intrusive ad containers, locked premium themes, and heavy telemetry.
CurseForge hosts Minecraft modpacks, World of Warcraft addons and other game mods, but the desktop app comes with ad containers, premium-only themes and telemetry.
**BetterCurseForge** restores a clean, fast, and customizable experience:
BetterCurseForge changes that:
- **Seamless Native UI**: Client themes appear natively under **Settings -> Themes** alongside official themes, complete with real-time live hover previews.
- **Unlocked Premium Themes**: Access all native CurseForge Premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Spookyforge*) without a subscription.
- **Zero-Ad Layouts**: Ad columns and sidebars are eliminated from the layout, letting modpack grids expand to fill your entire display.
- **Automated Update Resistance**: Never worry about CurseForge updates breaking your setup—**Auto-Repatch** automatically detects updates and re-applies the patch in seconds.
- **One-Click Reversible**: Easily unpatch anytime via the GUI or `BetterCurseForge.exe unpatch` to restore vanilla CurseForge.
- **Native theme picker**: Client themes appear in **Settings -> Themes** next to the official ones, with live hover previews.
- **Premium themes unlocked**: The official premium themes (*Pixelforge*, *Lifeforge*, *Fantasyforge*, *Spookyforge*) work without a subscription.
- **No ad columns**: Ad columns and sidebars are collapsed, so modpack grids use the full width of the window.
- **Survives updates**: When CurseForge updates, BetterCurseForge detects it and reapplies the patch in a few seconds.
- **Easy to undo**: Unpatch from the GUI or with `BetterCurseForge.exe unpatch` to get vanilla CurseForge back.
</div>